mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-04 21:19:27 +08:00
Compare commits
2 Commits
fd8606e69e
...
cefb1ead55
Author | SHA1 | Date | |
---|---|---|---|
|
cefb1ead55 | ||
|
15bb8ac97b |
@ -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",
|
||||
|
@ -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')}`,
|
||||
|
@ -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
|
||||
|
@ -12,6 +12,7 @@ import path from 'path';
|
||||
|
||||
export const globExcludeFiles = [
|
||||
'!src/**/__tests__',
|
||||
'!src/**/__benchmarks__',
|
||||
'!src/**/__test__',
|
||||
'!src/**/__e2e__',
|
||||
'!src/**/demos',
|
||||
|
73
packages/core/cli/src/commands/benchmark.js
Normal file
73
packages/core/cli/src/commands/benchmark.js
Normal 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]);
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
@ -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);
|
||||
|
@ -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';
|
||||
|
@ -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;
|
||||
|
||||
|
@ -115,9 +115,7 @@ describe('string field', () => {
|
||||
const model = await collection.model.create({
|
||||
name: ' n1\n ',
|
||||
});
|
||||
expect(model.toJSON()).toMatchObject({
|
||||
name: 'n1',
|
||||
});
|
||||
expect(model.get('name')).toBe('n1');
|
||||
});
|
||||
|
||||
it('trim when value is null should be null', async () => {
|
||||
@ -129,9 +127,7 @@ describe('string field', () => {
|
||||
const model = await collection.model.create({
|
||||
name: null,
|
||||
});
|
||||
expect(model.toJSON()).toMatchObject({
|
||||
name: null,
|
||||
});
|
||||
expect(model.get('name')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('when value is number should be convert to string', async () => {
|
||||
@ -143,8 +139,6 @@ describe('string field', () => {
|
||||
const model = await collection.model.create({
|
||||
name: 123,
|
||||
});
|
||||
expect(model.toJSON()).toMatchObject({
|
||||
name: '123',
|
||||
});
|
||||
expect(model.get('name')).toBe('123');
|
||||
});
|
||||
});
|
||||
|
@ -62,9 +62,7 @@ describe('text field', () => {
|
||||
const model = await collection.model.create({
|
||||
name: ' n1\n ',
|
||||
});
|
||||
expect(model.toJSON()).toMatchObject({
|
||||
name: 'n1',
|
||||
});
|
||||
expect(model.get('name')).toBe('n1');
|
||||
});
|
||||
|
||||
it('trim when value is null should be null', async () => {
|
||||
@ -76,9 +74,7 @@ describe('text field', () => {
|
||||
const model = await collection.model.create({
|
||||
name: null,
|
||||
});
|
||||
expect(model.toJSON()).toMatchObject({
|
||||
name: null,
|
||||
});
|
||||
expect(model.get('name')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('when value is number should be convert to string', async () => {
|
||||
@ -90,8 +86,6 @@ describe('text field', () => {
|
||||
const model = await collection.model.create({
|
||||
name: 123,
|
||||
});
|
||||
expect(model.toJSON()).toMatchObject({
|
||||
name: '123',
|
||||
});
|
||||
expect(model.get('name')).toBe('123');
|
||||
});
|
||||
});
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -20,12 +20,16 @@ export class StringField extends Field {
|
||||
}
|
||||
|
||||
additionalSequelizeOptions() {
|
||||
const { name, trim } = this.options;
|
||||
const { name, trim, unique } = this.options;
|
||||
|
||||
return {
|
||||
set(value) {
|
||||
if (unique && value === '') {
|
||||
value = null;
|
||||
}
|
||||
if (value == null) {
|
||||
return value;
|
||||
this.setDataValue(name, null);
|
||||
return;
|
||||
}
|
||||
if (typeof value !== 'string') {
|
||||
value = value.toString();
|
||||
|
@ -25,12 +25,16 @@ export class TextField extends Field {
|
||||
}
|
||||
|
||||
additionalSequelizeOptions() {
|
||||
const { name, trim } = this.options;
|
||||
const { name, trim, unique } = this.options;
|
||||
|
||||
return {
|
||||
set(value) {
|
||||
if (unique && value === '') {
|
||||
value = null;
|
||||
}
|
||||
if (value == null) {
|
||||
return value;
|
||||
this.setDataValue(name, null);
|
||||
return;
|
||||
}
|
||||
if (typeof value !== 'string') {
|
||||
value = value.toString();
|
||||
|
@ -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",
|
||||
|
@ -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';
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -28,7 +28,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",
|
||||
|
@ -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);
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user