Merge branch 'main' into next

This commit is contained in:
GitHub Actions Bot 2024-09-02 23:40:46 +00:00
commit fd9855cc0d
4 changed files with 131 additions and 2 deletions

View File

@ -55,6 +55,44 @@ export abstract class RelationRepository {
return this.db.getCollection(this.targetModel.name);
}
abstract find(options?: FindOptions): Promise<any>;
async chunk(
options: FindOptions & { chunkSize: number; callback: (rows: Model[], options: FindOptions) => Promise<void> },
) {
const { chunkSize, callback, limit: overallLimit } = options;
const transaction = await this.getTransaction(options);
let offset = 0;
let totalProcessed = 0;
// eslint-disable-next-line no-constant-condition
while (true) {
// Calculate the limit for the current chunk
const currentLimit = overallLimit !== undefined ? Math.min(chunkSize, overallLimit - totalProcessed) : chunkSize;
const rows = await this.find({
...options,
limit: currentLimit,
offset,
transaction,
});
if (rows.length === 0) {
break;
}
await callback(rows, options);
offset += currentLimit;
totalProcessed += rows.length;
if (overallLimit !== undefined && totalProcessed >= overallLimit) {
break;
}
}
}
convertTk(options: any) {
let tk = options;
if (typeof options === 'object' && options['tk']) {

View File

@ -0,0 +1,89 @@
import { createMockServer, MockServer } from '@nocobase/test';
import fs from 'fs';
import os from 'os';
import path from 'path';
import XLSX from 'xlsx';
describe('export action', () => {
let app: MockServer;
beforeEach(async () => {
app = await createMockServer({
plugins: ['nocobase'],
acl: false,
});
});
it('should export with association repository', async () => {
await app.db.getRepository('collections').create({
values: {
name: 'posts',
fields: [
{
name: 'title',
type: 'string',
},
{
name: 'comments',
type: 'hasMany',
target: 'comments',
},
],
},
context: {},
});
await app.db.getRepository('collections').create({
values: {
name: 'comments',
fields: [
{
name: 'content',
type: 'string',
},
],
},
context: {},
});
await app.db.getRepository('posts').create({
values: [
{
title: 'post1',
comments: [
{
content: 'comment1',
},
],
},
{
title: 'post2',
comments: [
{
content: 'comment2',
},
],
},
],
});
const res = await app
.agent()
.resource('posts.comments', 1)
.export({
values: {
columns: [{ dataIndex: ['content'], defaultTitle: 'content' }],
},
});
expect(res.status).toBe(200);
const buffer = res.body;
const workbook = XLSX.read(buffer, { type: 'buffer' });
const sheetName = workbook.SheetNames[0];
const sheet = workbook.Sheets[sheetName];
const rows = XLSX.utils.sheet_to_json(sheet);
expect(rows.length).toBe(1);
});
});

View File

@ -33,6 +33,7 @@ async function exportXlsxAction(ctx: Context, next: Next) {
const xlsxExporter = new XlsxExporter({
collectionManager: dataSource.collectionManager,
collection,
repository,
columns,
findOptions: {
filter,

View File

@ -29,6 +29,7 @@ type ExportColumn = {
type ExportOptions = {
collectionManager: ICollectionManager;
collection: ICollection;
repository?: any;
columns: Array<ExportColumn>;
findOptions?: FindOptions;
chunkSize?: number;
@ -51,7 +52,7 @@ class XlsxExporter {
constructor(private options: ExportOptions) {}
async run(ctx?): Promise<XLSX.WorkBook> {
const { collection, columns, chunkSize } = this.options;
const { collection, columns, chunkSize, repository } = this.options;
const workbook = XLSX.utils.book_new();
const worksheet = XLSX.utils.sheet_new();
@ -63,7 +64,7 @@ class XlsxExporter {
let startRowNumber = 2;
await collection.repository.chunk({
await (repository || collection.repository).chunk({
...this.getFindOptions(),
chunkSize: chunkSize || 200,
callback: async (rows, options) => {