Merge branch 'next' into develop

This commit is contained in:
nocobase[bot] 2025-05-01 09:54:05 +00:00
commit 543736b110
18 changed files with 253 additions and 13 deletions

View File

@ -32,6 +32,7 @@
"e2e": "nocobase e2e",
"ts": "nocobase test:server",
"tc": "nocobase test:client",
"benchmark": "nocobase benchmark",
"doc": "nocobase doc",
"doc:cn": "nocobase doc --lang=zh-CN",
"postinstall": "nocobase postinstall",

View File

@ -25,6 +25,7 @@ export const buildDeclaration = (cwd: string, targetDir: string) => {
`!${path.join(srcPath, '**/demos{,/**}')}`,
`!${path.join(srcPath, '**/__test__{,/**}')}`,
`!${path.join(srcPath, '**/__tests__{,/**}')}`,
`!${path.join(srcPath, '**/__benchmarks__{,/**}')}`,
`!${path.join(srcPath, '**/__e2e__{,/**}')}`,
`!${path.join(srcPath, '**/*.mdx')}`,
`!${path.join(srcPath, '**/*.md')}`,

View File

@ -15,6 +15,7 @@ import fs from 'fs-extra';
import path from 'path';
import { build as tsupBuild } from 'tsup';
import { RsdoctorRspackPlugin } from '@rsdoctor/rspack-plugin';
import { EsbuildSupportExts, globExcludeFiles } from './constant';
import { PkgLog, UserConfig, getPackageJson } from './utils';
import {
@ -26,12 +27,15 @@ import {
getSourcePackages,
} from './utils/buildPluginUtils';
import { getDepPkgPath, getDepsConfig } from './utils/getDepsConfig';
import { RsdoctorRspackPlugin } from '@rsdoctor/rspack-plugin';
const validExts = ['.ts', '.tsx', '.js', '.jsx', '.mjs'];
const serverGlobalFiles: string[] = ['src/**', '!src/client/**', ...globExcludeFiles];
const clientGlobalFiles: string[] = ['src/**', '!src/server/**', ...globExcludeFiles];
const sourceGlobalFiles: string[] = ['src/**/*.{ts,js,tsx,jsx,mjs}', '!src/**/__tests__'];
const sourceGlobalFiles: string[] = [
'src/**/*.{ts,js,tsx,jsx,mjs}',
'!src/**/__tests__',
'!src/**/__benchmarks__',
];
const external = [
// nocobase

View File

@ -12,6 +12,7 @@ import path from 'path';
export const globExcludeFiles = [
'!src/**/__tests__',
'!src/**/__benchmarks__',
'!src/**/__test__',
'!src/**/__e2e__',
'!src/**/demos',

View File

@ -0,0 +1,73 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
const glob = require('fast-glob');
const { Command } = require('commander');
const { run } = require('../util');
/**
*
* @param {Command} cli
*/
module.exports = (cli) => {
return (
cli
.command('benchmark')
.description('Run benchmark tests')
// .option('--single-thread [singleThread]')
.option('-a, --all [all]', 'Run all benchmark files which ends with .benchmark.{js,ts}')
.arguments('[paths...]')
.allowUnknownOption()
.action(async (paths, opts) => {
process.env.NODE_ENV = 'test';
process.env.LOGGER_LEVEL = 'error';
const cliArgs = ['--max_old_space_size=14096'];
// if (process.argv.includes('-h') || process.argv.includes('--help')) {
// await run('node', cliArgs);
// return;
// }
// if (!opts.singleThread) {
// process.argv.splice(process.argv.indexOf('--single-thread=false'), 1);
// } else {
// process.argv.push('--poolOptions.threads.singleThread=true');
// }
if (!paths.length) {
if (opts.all) {
paths.push('**/*.benchmark.ts');
} else {
console.warn(
'No benchmark files specified. Please provide at least 1 benchmark file or path to run. Or use --all to run all "*.benchmark.ts".',
);
return;
}
}
const files = [];
for (const pattern of paths) {
for (const file of glob.sync(pattern)) {
files.push(file);
}
}
if (!files.length) {
console.log('No benchmark files found');
return;
}
for (const file of files) {
await run('tsx', [...cliArgs, file]);
}
})
);
};

View File

@ -29,6 +29,7 @@ module.exports = (cli) => {
require('./pm2')(cli);
require('./test')(cli);
require('./test-coverage')(cli);
require('./benchmark')(cli);
require('./umi')(cli);
require('./update-deps')(cli);
require('./upgrade')(cli);

View File

@ -389,7 +389,7 @@ exports.initEnv = function initEnv() {
if (
!process.env.APP_ENV_PATH &&
process.argv[2] &&
['test', 'test:client', 'test:server'].includes(process.argv[2])
['test', 'test:client', 'test:server', 'benchmark'].includes(process.argv[2])
) {
if (fs.existsSync(resolve(process.cwd(), '.env.test'))) {
process.env.APP_ENV_PATH = '.env.test';

View File

@ -9,8 +9,10 @@
import { Collection, Database, createMockDatabase } from '@nocobase/database';
import { IdentifierError } from '../errors/identifier-error';
import { isPg } from '@nocobase/test';
const pgOnly = () => (isPg() ? it : it.skip);
const pgOnly = () => (process.env.DB_DIALECT == 'postgres' ? it : it.skip);
describe('collection', () => {
let db: Database;

View File

@ -8,7 +8,9 @@
*/
import { BelongsToManyRepository, Collection, createMockDatabase, Database } from '@nocobase/database';
import { pgOnly } from '@nocobase/test';
import { isPg } from '@nocobase/test';
const pgOnly = () => (isPg() ? describe : describe.skip);
pgOnly()('belongs to many with targetCollection', () => {
let db: Database;

View File

@ -8,8 +8,10 @@
*/
import { createMockDatabase, Database, ViewFieldInference } from '@nocobase/database';
import { pgOnly } from '@nocobase/test';
import { uid } from '@nocobase/utils';
import { isPg } from '@nocobase/test';
const pgOnly = () => (isPg() ? describe : describe.skip);
pgOnly()('view with association', () => {
let db: Database;

View File

@ -36,6 +36,7 @@
"react-dom": "^18.0.0",
"rimraf": "^3.0.0",
"serve": "^14.2.4",
"tinybench": "^4.0.1",
"ts-loader": "^7.0.4",
"ts-node": "9.1.1",
"ts-node-dev": "1.1.8",

View File

@ -7,7 +7,6 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { describe } from 'vitest';
import ws from 'ws';
export { createMockDatabase, MockDatabase, mockDatabase } from '@nocobase/database';
@ -16,7 +15,6 @@ export * from './memory-pub-sub-adapter';
export * from './mock-isolated-cluster';
export * from './mock-server';
export const pgOnly: () => any = () => (process.env.DB_DIALECT == 'postgres' ? describe : describe.skip);
export const isPg = () => process.env.DB_DIALECT == 'postgres';
export const isMysql = () => process.env.DB_DIALECT == 'mysql';

View File

@ -7,9 +7,11 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { MockServer, pgOnly } from '@nocobase/test';
import { isPg, MockServer } from '@nocobase/test';
import { createApp } from '..';
const pgOnly = () => (isPg() ? describe : describe.skip);
pgOnly()('Inherited Collection', () => {
let app: MockServer;
let agent;

View File

@ -9,8 +9,10 @@
import Database, { Repository } from '@nocobase/database';
import Application from '@nocobase/server';
import { isPg } from '@nocobase/test';
import { createApp } from '..';
import { pgOnly } from '@nocobase/test';
const pgOnly = () => (isPg() ? describe : describe.skip);
pgOnly()('Inherited Collection with schema options', () => {
let db: Database;

View File

@ -14,9 +14,11 @@ import Database, {
Repository,
} from '@nocobase/database';
import Application from '@nocobase/server';
import { pgOnly } from '@nocobase/test';
import { isPg } from '@nocobase/test';
import { createApp } from '..';
const pgOnly = () => (isPg() ? describe : describe.skip);
pgOnly()('Inherited Collection', () => {
let db: Database;
let app: Application;

View File

@ -8,10 +8,12 @@
*/
import { Database, MigrationContext } from '@nocobase/database';
import { MockServer, pgOnly } from '@nocobase/test';
import { MockServer, isPg } from '@nocobase/test';
import Migrator from '../../migrations/20230918024546-set-collection-schema';
import { createApp } from '../index';
const pgOnly = () => (isPg() ? describe : describe.skip);
pgOnly()('set collection schema', () => {
let app: MockServer;
let db: Database;

View File

@ -29,7 +29,8 @@
"react-i18next": "^11.15.1",
"react-js-cron": "^3.1.0",
"react-router-dom": "^6.11.2",
"sequelize": "^6.26.0"
"sequelize": "^6.26.0",
"tinybench": "4.x"
},
"peerDependencies": {
"@nocobase/actions": "1.x",

View File

@ -0,0 +1,145 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { Bench } from 'tinybench';
import { getApp } from '@nocobase/plugin-workflow-test';
import Plugin from '..';
async function run(app, fn, args) {
const db = app.db;
const WorkflowRepo = db.getCollection('workflows').repository;
const workflow = await WorkflowRepo.create({
values: {
enabled: true,
sync: true,
type: 'syncTrigger',
},
});
await fn({ app, workflow }, args);
}
async function loopEcho({ app, workflow }, target) {
const plugin = app.pm.get(Plugin) as Plugin;
const loopNode = await workflow.createNode({
type: 'loop',
config: {
target,
},
});
await workflow.createNode({
type: 'echo',
upstreamId: loopNode.id,
branchIndex: 0,
});
await plugin.trigger(workflow, {});
}
async function loopQuery({ app, workflow }, target) {
const plugin = app.pm.get(Plugin) as Plugin;
const loopNode = await workflow.createNode({
type: 'loop',
config: {
target,
},
});
await workflow.createNode({
type: 'query',
config: {
collection: 'posts',
params: {
filterByTk: Math.ceil(Math.random() * 1000),
},
},
upstreamId: loopNode.id,
branchIndex: 0,
});
await plugin.trigger(workflow, {});
}
async function loopCreate({ app, workflow }, target) {
const plugin = app.pm.get(Plugin) as Plugin;
const loopNode = await workflow.createNode({
type: 'loop',
config: {
target,
},
});
await workflow.createNode({
type: 'create',
config: {
collection: 'posts',
params: {
values: {},
},
},
upstreamId: loopNode.id,
branchIndex: 0,
});
await plugin.trigger(workflow, {});
}
async function benchmark() {
const app = await getApp({
plugins: ['workflow-loop'],
});
const PostModel = app.db.getCollection('posts').model;
await PostModel.bulkCreate(Array.from({ length: 1000 }, (_, i) => ({ title: `test-${i}` })));
const bench = new Bench()
.add('1 node', async () => {
await run(app, loopEcho, 0);
})
.add('20 nodes: loop 10 echos', async () => {
await run(app, loopEcho, 10);
})
.add('200 nodes: loop 100 echos', async () => {
await run(app, loopEcho, 100);
})
.add('20 nodes: loop 10 queries', async () => {
await run(app, loopQuery, 10);
})
.add('200 nodes: loop 100 queries', async () => {
await run(app, loopQuery, 100);
})
.add('20 nodes: loop 10 creates', async () => {
await run(app, loopCreate, 10);
})
.add('200 nodes: loop 100 creates', async () => {
await run(app, loopCreate, 100);
});
await bench.run();
await app.cleanDb();
await app.destroy();
console.table(bench.table());
}
benchmark()
.then(() => {
process.exit(0);
})
.catch((err) => {
console.error(err);
process.exit(1);
});