feat: create nocobase app with simple & quickstart option (#87)

* feat: create nocobase app with simple & quickstart option

* chore: delete template file

* create-nocobase-app: add env API_PORT fallback

* chore: log

* env default fallback

* move config dir

* change has yarn

* chore: prettier

* fix: npm running issue

* database testing support sqlite

* once...

* chore: typo

* fix: sqlite test

* update readme

* feat: copy .env.example to .env at create-nocobase-app

* create-nocobase-app: change sqlite3 to github master

* create-nocobase-app: .env template

* create-nocobase-app: update .env

* chore: typo

* update README

* chore: Application constructor

* feat: sqlite demo data support

* fix test

* fix: application error

* chore: plugin-client run sql

* fix: application createCli

* fix: can choose whether to register actions

* chore: model compile error

* fix: support sqlite

* fix: demo data set index sequence on postgresql

* chore: code reduce

* fix: operators are compatible with sqlite

* add impor demo option to init command

* update env

Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
ChengLei Shao 2021-10-18 12:49:37 +08:00 committed by GitHub
parent 12b3590845
commit 05ecb25d1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 1433 additions and 659 deletions

2
.gitignore vendored
View File

@ -20,3 +20,5 @@ uploads/
/.idea /.idea
.vercel .vercel
packages/database/src/__tests__/.db
db.sqlite

View File

@ -60,19 +60,34 @@ Node:
Database: Database:
- PostgreSQL 10.x+ - PostgreSQL 10.x+
- Sqlite 3+
Installation Installation
---------- ----------
### Create a project with `create-nocobase-app` ### Create a project with `create-nocobase-app`
#### Quickstart
~~~shell ~~~shell
mkdir my-nocobase-app && cd my-nocobase-app yarn create nocobase-app my-nocobase-app --quickstart
yarn create nocobase-app ~~~
cp .env.example .env
#### Start with configuration
~~~shell
# 1. create project
yarn create nocobase-app my-nocobase-app
cd my-nocobase-app
# 2. edit configuration in .env file
vim .env
# 3. start a database (optional)
docker-compose up -d postgres docker-compose up -d postgres
yarn install
yarn nocobase init # 4. create initialization data
yarn nocobase init --import-demo
# 5. start project
yarn start yarn start
~~~ ~~~

View File

@ -62,23 +62,38 @@ Node:
Database: Database:
- PostgreSQL 10.x+ - PostgreSQL 10.x+
- Sqlite 3+
安装 & 运行 安装 & 运行
---------- ----------
### 通过 `create-nocobase-app` 创建项目 ### 通过 `create-nocobase-app` 创建项目
#### 快速启动方式
~~~shell ~~~shell
mkdir my-nocobase-app && cd my-nocobase-app yarn create nocobase-app my-nocobase-app --quickstart
yarn create nocobase-app ~~~
cp .env.example .env
#### 自定义启动方式
~~~shell
# 1. 创建项目
yarn create nocobase-app my-nocobase-app
cd my-nocobase-app
# 2. 修改.env中对应的数据库配置
vim .env
# 3. 启动预置数据库(可选)
docker-compose up -d postgres docker-compose up -d postgres
yarn install
yarn nocobase init # 4. 初始化数据
yarn nocobase init --import-demo
# 5. 启动项目
yarn start yarn start
~~~ ~~~
浏览器内打开 http://localhost:8000 使用浏览器打开 http://localhost:8000
### 使用 docker compose ### 使用 docker compose

View File

@ -68,6 +68,7 @@
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-test-renderer": "^17.0.2", "react-test-renderer": "^17.0.2",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"sqlite3": "^5.0.2",
"supertest": "^6.1.3", "supertest": "^6.1.3",
"ts-jest": "^26.5.6", "ts-jest": "^26.5.6",
"ts-node": "^9.1.1", "ts-node": "^9.1.1",

View File

@ -4,7 +4,18 @@ import path from 'path';
const start = Date.now(); const start = Date.now();
const api = new Server({ const api = new Server({
database: { database: process.env.DB_DIALECT === 'sqlite' ? {
dialect: process.env.DB_DIALECT as any,
storage: path.resolve(process.cwd(), './db.sqlite'),
logging: process.env.DB_LOG_SQL === 'on' ? console.log : false,
define: {},
sync: {
force: false,
alter: {
drop: false,
},
},
} : {
username: process.env.DB_USER, username: process.env.DB_USER,
password: process.env.DB_PASSWORD, password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE, database: process.env.DB_DATABASE,
@ -59,7 +70,7 @@ for (const plugin of plugins) {
api.plugin( api.plugin(
require(`@nocobase/plugin-client/${libDir}/server`).default, { require(`@nocobase/plugin-client/${libDir}/server`).default, {
dist: path.resolve(process.cwd(), './dist'), dist: path.resolve(process.cwd(), './dist'),
importDemo: true, // importDemo: true,
}); });
if (process.argv.length < 3) { if (process.argv.length < 3) {
@ -67,7 +78,6 @@ if (process.argv.length < 3) {
process.argv.push('start', '--port', process.env.API_PORT); process.argv.push('start', '--port', process.env.API_PORT);
} }
console.log(process.argv);
api.parse(process.argv).then(() => { api.parse(process.argv).then(() => {
console.log(`Start-up time: ${(Date.now() - start) / 1000}s`); console.log(`Start-up time: ${(Date.now() - start) / 1000}s`);

View File

@ -15,7 +15,10 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@umijs/utils": "3.5.17" "@umijs/utils": "3.5.17",
"commander": "^8.2.0",
"execa": "^5.1.1",
"ora": "^5.4.1"
}, },
"bin": { "bin": {
"create-nocobase-app": "bin/create-nocobase-app.js" "create-nocobase-app": "bin/create-nocobase-app.js"

View File

@ -2,11 +2,18 @@ import { Generator } from '@umijs/utils';
import { join } from 'path'; import { join } from 'path';
export default class AppGenerator extends Generator { export default class AppGenerator extends Generator {
private tplContext = {};
setTplContext(context) {
this.tplContext = context;
}
async writing() { async writing() {
this.copyDirectory({ this.copyDirectory({
context: { context: {
version: require('../../package').version, version: require('../../package').version,
conventionRoutes: this.args.conventionRoutes, conventionRoutes: this.args.conventionRoutes,
...this.tplContext
}, },
path: join(__dirname, '../../templates/AppGenerator'), path: join(__dirname, '../../templates/AppGenerator'),
target: this.cwd, target: this.cwd,

View File

@ -1,30 +1,107 @@
import { chalk, yParser } from '@umijs/utils'; import { chalk } from '@umijs/utils';
import { existsSync } from 'fs'; import commander from 'commander';
import { join } from 'path'; import path from 'path';
import ora from 'ora';
import { hasYarn, runInit, runInstall, runStart } from './utils';
import execa from 'execa';
const args = yParser(process.argv.slice(2), { const packageJson = require('../package.json');
alias: {
version: ['v'], const program = new commander.Command(packageJson.name)
help: ['h'], .version(packageJson.version)
}, .option('--simple', 'create nocobase app without install dependencies')
boolean: ['version'], .option('--quickstart', 'create quickstart nocobase app')
.arguments('<project-directory>')
.usage(`${chalk.green('<project-directory>')}`)
.action(async (directory, options) => {
console.log(
`Creating a new Nocobase application at ${chalk.green(directory)}.`,
);
console.log('Creating files.');
const fullPath = path.join(process.cwd(), directory);
await require('./index').default({
cwd: fullPath,
args: {},
tplContext: options.quickstart
? { quickstart: true }
: { quickstart: false },
}); });
if (args.version && !args._[0]) { const cmd = chalk.cyan(hasYarn() ? 'yarn' : 'npm run');
args._[0] = 'version';
const local = existsSync(join(__dirname, '../.local')) if (options.simple) {
? chalk.cyan('@local') console.log();
: ''; console.log('Done. You can start by doing:');
const { name, version } = require('../package.json'); console.log();
console.log(`${name}@${version}${local}`); console.log(` ${chalk.cyan('cd')} ${directory}`);
} else { console.log(` ${cmd} install`);
require('./') console.log(` ${cmd} nocobase init --import-demo`);
.default({ console.log(` ${cmd} start`);
cwd: process.cwd(), console.log();
args, return;
})
.catch((err: Error) => {
console.error(`Create failed, ${err.message}`);
console.error(err);
});
} }
const installPrefix = chalk.yellow('Installing dependencies:');
const loader = ora(installPrefix).start();
const logInstall = (chunk = '') => {
loader.text = `${installPrefix} ${chunk
.toString()
.split('\n')
.join(' ')}`;
};
const runner = runInstall(fullPath);
runner?.stdout?.on('data', logInstall);
runner?.stderr?.on('data', logInstall);
await runner;
loader.stop();
console.log(`Dependencies installed ${chalk.green('successfully')}.`);
console.log();
console.log(`Your application was created at ${chalk.green(directory)}.\n`);
if (options.quickstart) {
// Using Sqlite as Database
const prefix = chalk.yellow('Nocobase init');
const initLoader = ora(prefix).start();
try {
const initLog = (chunk = '') => {
initLoader.text = `${prefix} ${chunk
.toString()
.split('\n')
.join(' ')}`;
};
const init = runInit(fullPath);
init.stderr.on('data', initLog);
init.stdout.on('data', initLog);
await init;
initLoader.stop();
} catch (e) {
initLoader.stop();
console.log();
console.log(e.message);
process.exit(1);
}
console.log(`Running your application.`);
await execa('npm', ['run', 'start'], {
stdio: 'inherit',
cwd: fullPath,
});
} else {
console.log();
console.log('You can start by doing:');
console.log();
console.log(` ${chalk.cyan('cd')} ${directory}`);
console.log(` ${cmd} nocobase init --import-demo`);
console.log(` ${cmd} start`);
console.log();
}
})
.showHelpAfterError()
.parse(process.argv);

View File

@ -4,13 +4,17 @@ import AppGenerator from './AppGenerator/AppGenerator';
export default async ({ export default async ({
cwd, cwd,
args, args,
tplContext
}: { }: {
cwd: string; cwd: string;
args: yargs.Arguments; args: yargs.Arguments;
tplContext: object
}) => { }) => {
const generator = new AppGenerator({ const generator = new AppGenerator({
cwd, cwd,
args, args,
}); });
generator.setTplContext(tplContext);
await generator.run(); await generator.run();
}; };

View File

@ -0,0 +1,28 @@
import execa from 'execa';
export function hasYarn() {
return (process.env.npm_config_user_agent || '').indexOf('yarn') === 0;
}
function runYarn(path: string, args: string[]) {
if (hasYarn()) {
return execa('yarn', args, {
cwd: path,
stdin: 'ignore',
});
}
return execa('npm', args, { cwd: path, stdin: 'ignore' });
}
export function runInstall(path) {
return runYarn(path, ['install']);
}
export function runStart(path) {
return runYarn(path, ['run', 'start']);
}
export function runInit(path) {
return runYarn(path, ['run', 'nocobase', 'init', '--import-demo']);
}

View File

@ -1,34 +1,25 @@
########## DOCKER COMPOSE ENV ########## ########## DOCKER COMPOSE ENV ##########
DB_POSTGRES_PORT=15432 ADMINER_PORT=8080
APP_PORT=13000 DB_MYSQL_PORT=3306
ADMINER_PORT=18080 DB_POSTGRES_PORT=5432
VERDACCIO_PORT=4873
APP_PORT=13001
API_PORT=13002
########## NOCOBASE ENV ########## ########## NOCOBASE ENV ##########
# DATABASE # DATABASE
DB_DIALECT=postgres DB_DIALECT=postgres
DB_HOST=localhost
DB_PORT=5432
DB_DATABASE=nocobase DB_DATABASE=nocobase
DB_USER=nocobase DB_USER=nocobase
DB_PASSWORD=nocobase DB_PASSWORD=nocobase
# set to 'on' to enable log # set to 'on' to enable log
DB_LOG_SQL= DB_LOG_SQL=
# for localhost
DB_PORT=15432
DB_HOST=localhost
# for docker
# DB_PORT=5432
# DB_HOST=postgres
# API & APP
NOCOBASE_ENV=
API_PORT=13001
API_URL=/api/
# ADMIN USER (Initialization only) # ADMIN USER (Initialization only)
ADMIN_EMAIL=admin@nocobase.com ADMIN_EMAIL=admin@nocobase.com
@ -41,4 +32,11 @@ STORAGE_TYPE=local
# LOCAL STORAGE # LOCAL STORAGE
LOCAL_STORAGE_USE_STATIC_SERVER=true LOCAL_STORAGE_USE_STATIC_SERVER=true
LOCAL_STORAGE_BASE_URL=http://localhost:23000 LOCAL_STORAGE_BASE_URL=http://localhost:13002
# ALI OSS STORAGE
ALI_OSS_STORAGE_BASE_URL=
ALI_OSS_REGION=oss-cn-beijing
ALI_OSS_ACCESS_KEY_ID=
ALI_OSS_ACCESS_KEY_SECRET=
ALI_OSS_BUCKET=

View File

@ -0,0 +1,47 @@
########## DOCKER COMPOSE ENV ##########
ADMINER_PORT=8080
DB_MYSQL_PORT=3306
DB_POSTGRES_PORT=5432
VERDACCIO_PORT=4873
APP_PORT=13001
API_PORT=13002
########## NOCOBASE ENV ##########
# DATABASE
{{#quickstart}}
DB_DIALECT=sqlite
DB_STORAGE=db.sqlite
{{/quickstart}}
{{^quickstart}}
DB_DIALECT=postgres
DB_HOST=localhost
DB_PORT=5432
DB_DATABASE=nocobase
DB_USER=nocobase
DB_PASSWORD=nocobase
{{/quickstart}}
# set to 'on' to enable log
DB_LOG_SQL=
# ADMIN USER (Initialization only)
ADMIN_EMAIL=admin@nocobase.com
ADMIN_PASSWORD=admin
# STORAGE (Initialization only)
# local or ali-oss
STORAGE_TYPE=local
# LOCAL STORAGE
LOCAL_STORAGE_USE_STATIC_SERVER=true
LOCAL_STORAGE_BASE_URL=http://localhost:13002
# ALI OSS STORAGE
ALI_OSS_STORAGE_BASE_URL=
ALI_OSS_REGION=oss-cn-beijing
ALI_OSS_ACCESS_KEY_ID=
ALI_OSS_ACCESS_KEY_SECRET=
ALI_OSS_BUCKET=

View File

@ -11,12 +11,12 @@ export default defineConfig({
type: 'none', type: 'none',
}, },
define: { define: {
'process.env.API_URL': process.env.API_URL, 'process.env.API_URL': process.env.API_URL || "http://127.0.0.1",
'process.env.API_PORT': process.env.API_PORT, 'process.env.API_PORT': process.env.API_PORT || "13001",
}, },
proxy: { proxy: {
'/api': { '/api': {
'target': `http://localhost:${process.env.API_PORT}/`, 'target': `http://localhost:${process.env.API_PORT || "13001"}/`,
'changeOrigin': true, 'changeOrigin': true,
'pathRewrite': { '^/api': '/api' }, 'pathRewrite': { '^/api': '/api' },
}, },

View File

@ -5,7 +5,7 @@
"start": "concurrently \"npm run start-server\" \"umi dev\"", "start": "concurrently \"npm run start-server\" \"umi dev\"",
"start-client": "umi dev", "start-client": "umi dev",
"start-server": "ts-node-dev -r dotenv/config --project tsconfig.apis.json ./src/apis/index.ts", "start-server": "ts-node-dev -r dotenv/config --project tsconfig.apis.json ./src/apis/index.ts",
"nocobase": "ts-node-dev -r dotenv/config --project tsconfig.apis.json ./src/apis/index.ts", "nocobase": "ts-node -r dotenv/config --project tsconfig.apis.json ./src/apis/index.ts",
"serve": "node -r dotenv/config ./lib/apis/index.js", "serve": "node -r dotenv/config ./lib/apis/index.js",
"build": "npm run build-server && npm run build-client", "build": "npm run build-server && npm run build-client",
"build-client": "umi build", "build-client": "umi build",
@ -27,7 +27,8 @@
] ]
}, },
"dependencies": { "dependencies": {
"@nocobase/plugin-action-logs": "^{{{ version }}}", {{#quickstart}}"sqlite3": "https://github.com/mapbox/node-sqlite3/tarball/master",
{{/quickstart}}"@nocobase/plugin-action-logs": "^{{{ version }}}",
"@nocobase/plugin-china-region": "^{{{ version }}}", "@nocobase/plugin-china-region": "^{{{ version }}}",
"@nocobase/plugin-client": "^{{{ version }}}", "@nocobase/plugin-client": "^{{{ version }}}",
"@nocobase/plugin-collections": "^{{{ version }}}", "@nocobase/plugin-collections": "^{{{ version }}}",

View File

@ -0,0 +1,36 @@
import { DatabaseOptions } from '@nocobase/database';
{{#quickstart}}
export default {
dialect: process.env.DB_DIALECT,
dialectModule: require('sqlite3'),
storage: process.env.DB_STORAGE
} as DatabaseOptions;
{{/quickstart}}
{{^quickstart}}
export default {
username: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
host: process.env.DB_HOST,
port: process.env.DB_PORT as any,
dialect: process.env.DB_DIALECT as any,
dialectOptions: {
charset: 'utf8mb4',
collate: 'utf8mb4_unicode_ci',
},
pool: {
max: 5,
min: 0,
acquire: 60000,
idle: 10000,
},
logging: process.env.DB_LOG_SQL === 'on' ? console.log : false,
define: {},
sync: {
force: false,
alter: {
drop: false,
},
},
} as DatabaseOptions;
{{/quickstart}}

View File

@ -1,35 +1,10 @@
import Server from '@nocobase/server';
import path from 'path'; import path from 'path';
import Application from '@nocobase/server';
const start = Date.now(); const start = Date.now();
const api = new Server({ const api = new Application({
database: { database: require('./config/db').default,
username: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
host: process.env.DB_HOST,
port: process.env.DB_PORT as any,
dialect: process.env.DB_DIALECT as any,
dialectOptions: {
charset: 'utf8mb4',
collate: 'utf8mb4_unicode_ci',
},
pool: {
max: 5,
min: 0,
acquire: 60000,
idle: 10000,
},
logging: process.env.DB_LOG_SQL === 'on' ? console.log : false,
define: {},
sync: {
force: false,
alter: {
drop: false,
},
},
},
resourcer: { resourcer: {
prefix: '/api', prefix: '/api',
}, },
@ -49,24 +24,19 @@ const plugins = [
]; ];
for (const plugin of plugins) { for (const plugin of plugins) {
api.plugin( api.plugin(require(`${plugin}/lib/server`).default);
require(`${plugin}/lib/server`).default,
);
} }
api.plugin( api.plugin(require(`@nocobase/plugin-client/lib/server`).default, {
require(`@nocobase/plugin-client/lib/server`).default, {
dist: path.resolve(process.cwd(), './dist'), dist: path.resolve(process.cwd(), './dist'),
importDemo: true, importDemo: true,
}); });
if (process.argv.length < 3) { if (process.argv.length < 3) {
// @ts-ignore // @ts-ignore
process.argv.push('start', '--port', process.env.API_PORT); process.argv.push('start', '--port', process.env.API_PORT || '13001');
} }
console.log(process.argv);
api.parse(process.argv).then(() => { api.parse(process.argv).then(() => {
console.log(`Start-up time: ${(Date.now() - start) / 1000}s`); console.log(`Start-up time: ${(Date.now() - start) / 1000}s`);
}); });

View File

@ -10,7 +10,7 @@
"bcrypt": "^5.0.0", "bcrypt": "^5.0.0",
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",
"glob": "^7.1.6", "glob": "^7.1.6",
"sequelize": "^6.3.3" "sequelize": "6.7.0"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -11,13 +11,13 @@ describe('radio', () => {
fields: [ fields: [
{ {
type: 'string', type: 'string',
name: 'name' name: 'name',
}, },
{ {
type: 'hasMany', type: 'hasMany',
name: 'posts' name: 'posts',
} },
] ],
}); });
db.table({ db.table({
@ -38,25 +38,25 @@ describe('radio', () => {
}, },
{ {
type: 'radio', type: 'radio',
name: 'pinned' name: 'pinned',
}, },
{ {
type: 'radio', type: 'radio',
name: 'latest', name: 'latest',
defaultValue: true defaultValue: true,
}, },
{ {
type: 'radio', type: 'radio',
name: 'pinned_in_status', name: 'pinned_in_status',
scope: ['status'] scope: ['status'],
}, },
{ {
type: 'radio', type: 'radio',
name: 'pinned_in_user', name: 'pinned_in_user',
scope: ['user'], scope: ['user'],
defaultValue: true defaultValue: true,
} },
] ],
}); });
await db.sync({ force: true }); await db.sync({ force: true });
@ -79,7 +79,7 @@ describe('radio', () => {
expect(posts.map(({ pinned, latest }) => ({ pinned, latest }))).toEqual([ expect(posts.map(({ pinned, latest }) => ({ pinned, latest }))).toEqual([
{ pinned: true, latest: false }, { pinned: true, latest: false },
{ pinned: false, latest: true } { pinned: false, latest: true },
]); ]);
}); });
@ -107,7 +107,7 @@ describe('radio', () => {
expect(posts.map(({ pinned, latest }) => ({ pinned, latest }))).toEqual([ expect(posts.map(({ pinned, latest }) => ({ pinned, latest }))).toEqual([
{ pinned: false, latest: false }, { pinned: false, latest: false },
{ pinned: true, latest: false }, { pinned: true, latest: false },
{ pinned: false, latest: true } { pinned: false, latest: true },
]); ]);
}); });
@ -117,25 +117,50 @@ describe('radio', () => {
const Post = db.getModel('posts'); const Post = db.getModel('posts');
const bulkCreated = await Post.bulkCreate([ const bulkCreated = await Post.bulkCreate([
{ title: 'title1', status: 'published', user_id: 1 }, { title: 'title1', status: 'published', user_id: 1 },
{ title: 'title2', status: 'published', user_id: 2, pinned_in_status: true }, {
{ title: 'title3', status: 'draft', user_id: 1, pinned_in_status: true }, title: 'title2',
status: 'published',
user_id: 2,
pinned_in_status: true,
},
{
title: 'title3',
status: 'draft',
user_id: 1,
pinned_in_status: true,
},
]); ]);
expect(bulkCreated.map(({ pinned_in_status, pinned_in_user }) => ({ pinned_in_status, pinned_in_user }))).toEqual([ expect(
bulkCreated.map(({ pinned_in_status, pinned_in_user }) => ({
pinned_in_status,
pinned_in_user,
})),
).toEqual([
{ pinned_in_status: false, pinned_in_user: false }, { pinned_in_status: false, pinned_in_user: false },
{ pinned_in_status: true, pinned_in_user: true }, { pinned_in_status: true, pinned_in_user: true },
{ pinned_in_status: true, pinned_in_user: true } { pinned_in_status: true, pinned_in_user: true },
]); ]);
const user1Post = await users[1].createPost({ title: 'title4', status: 'draft', pinned_in_status: true }); const user1Post = await users[1].createPost({
title: 'title4',
status: 'draft',
pinned_in_status: true,
});
expect(user1Post.pinned_in_status).toBe(true); expect(user1Post.pinned_in_status).toBe(true);
expect(user1Post.pinned_in_user).toBe(true); expect(user1Post.pinned_in_user).toBe(true);
const posts = await Post.findAll({ order: [['id', 'ASC']] }); const posts = await Post.findAll({ order: [['id', 'ASC']] });
expect(posts.map(({ title, pinned_in_status, pinned_in_user }) => ({ title, pinned_in_status, pinned_in_user }))).toMatchObject([ expect(
posts.map(({ title, pinned_in_status, pinned_in_user }) => ({
title,
pinned_in_status,
pinned_in_user,
})),
).toMatchObject([
{ title: 'title1', pinned_in_status: false, pinned_in_user: false }, { title: 'title1', pinned_in_status: false, pinned_in_user: false },
{ title: 'title2', pinned_in_status: true, pinned_in_user: false }, { title: 'title2', pinned_in_status: true, pinned_in_user: false },
{ title: 'title3', pinned_in_status: false, pinned_in_user: true }, { title: 'title3', pinned_in_status: false, pinned_in_user: true },
{ title: 'title4', pinned_in_status: true, pinned_in_user: true } { title: 'title4', pinned_in_status: true, pinned_in_user: true },
]); ]);
}); });
}); });
@ -145,13 +170,13 @@ describe('radio', () => {
const Post = db.getModel('posts'); const Post = db.getModel('posts');
await Post.bulkCreate([ await Post.bulkCreate([
{ title: 'title1', pinned: true }, { title: 'title1', pinned: true },
{ title: 'title2' } { title: 'title2' },
]); ]);
const created = await Post.create({ pinned: false }); const created = await Post.create({ pinned: false });
expect(created.pinned).toBe(false); expect(created.pinned).toBe(false);
const posts = await Post.findAll({ order: [['title', 'ASC']] }); const posts = await Post.findAll({ order: [['id', 'ASC']] });
expect(posts.map(({ pinned }) => pinned)).toEqual([true, false, false]); expect(posts.map(({ pinned }) => pinned)).toEqual([true, false, false]);
}); });
@ -160,13 +185,13 @@ describe('radio', () => {
const Post = db.getModel('posts'); const Post = db.getModel('posts');
await Post.bulkCreate([ await Post.bulkCreate([
{ title: 'title1', pinned: true }, { title: 'title1', pinned: true },
{ title: 'title2' } { title: 'title2' },
]); ]);
const created = await Post.create({ pinned: true }); const created = await Post.create({ pinned: true });
expect(created.pinned).toBe(true); expect(created.pinned).toBe(true);
const posts = await Post.findAll({ order: [['title', 'ASC']] }); const posts = await Post.findAll({ order: [['id', 'ASC']] });
expect(posts.map(({ pinned }) => pinned)).toEqual([false, false, true]); expect(posts.map(({ pinned }) => pinned)).toEqual([false, false, true]);
}); });
@ -176,7 +201,7 @@ describe('radio', () => {
await Post.bulkCreate([ await Post.bulkCreate([
{ title: 'bug1' }, { title: 'bug1' },
{ title: 'bug2' }, { title: 'bug2' },
{ title: 'bug3' } { title: 'bug3' },
]); ]);
const post = await Post.findByPk(2); const post = await Post.findByPk(2);
@ -186,7 +211,7 @@ describe('radio', () => {
}); });
await post.update({ await post.update({
status: 'draft' status: 'draft',
}); });
const posts = await Post.findAll({ order: [['id', 'ASC']] }); const posts = await Post.findAll({ order: [['id', 'ASC']] });

View File

@ -33,20 +33,28 @@ describe('field types', () => {
const table = db.table({ const table = db.table({
name: 'test', name: 'test',
}); });
const field = buildField({ const field = buildField(
{
type: actual, type: actual,
name: 'test', name: 'test',
}, { },
{
sourceTable: table, sourceTable: table,
database: db, database: db,
}); },
);
expect(field).toBeInstanceOf(expected); expect(field).toBeInstanceOf(expected);
if (field instanceof Column) { if (field instanceof Column) {
const { type } = field.getAttributeOptions() as any; const { type } = field.getAttributeOptions() as any;
if (actual instanceof ABSTRACT) { if (actual instanceof ABSTRACT) {
expect(type).toBeInstanceOf(field.getDataType()); expect(type).toBeInstanceOf(field.getDataType());
// postgres 的 text 不限制长度,无需参数 // postgres 的 text 不限制长度,无需参数
if (db.sequelize.getDialect() !== 'postgres' || getDataTypeKey(type) !== 'TEXT') { if (
db.sequelize.getDialect() !== 'postgres' ||
getDataTypeKey(type) !== 'TEXT'
) {
// 非严谨比较undefined == null // 非严谨比较undefined == null
expect(type).toEqual(actual); expect(type).toEqual(actual);
} }
@ -58,7 +66,7 @@ describe('field types', () => {
} }
} }
db.close(); db.close();
} };
it('shound be boolean', () => { it('shound be boolean', () => {
assertTypeInstanceOf(Boolean, 'boolean'); assertTypeInstanceOf(Boolean, 'boolean');
@ -69,9 +77,12 @@ describe('field types', () => {
assertTypeInstanceOf(Integer, 'int'); assertTypeInstanceOf(Integer, 'int');
assertTypeInstanceOf(Integer, 'integer'); assertTypeInstanceOf(Integer, 'integer');
assertTypeInstanceOf(Integer, DataTypes.INTEGER); assertTypeInstanceOf(Integer, DataTypes.INTEGER);
assertTypeInstanceOf(Integer, DataTypes.INTEGER({ assertTypeInstanceOf(
Integer,
DataTypes.INTEGER({
length: 5, length: 5,
})); }),
);
}); });
it('shound be tiny integer', () => { it('shound be tiny integer', () => {
@ -80,9 +91,12 @@ describe('field types', () => {
assertTypeInstanceOf(Integer, 'tinyinteger'); assertTypeInstanceOf(Integer, 'tinyinteger');
assertTypeInstanceOf(Integer, 'tinyInteger'); assertTypeInstanceOf(Integer, 'tinyInteger');
assertTypeInstanceOf(Integer, DataTypes.TINYINT); assertTypeInstanceOf(Integer, DataTypes.TINYINT);
assertTypeInstanceOf(Integer, DataTypes.TINYINT({ assertTypeInstanceOf(
Integer,
DataTypes.TINYINT({
length: 5, length: 5,
})); }),
);
}); });
it('shound be small integer', () => { it('shound be small integer', () => {
@ -91,9 +105,12 @@ describe('field types', () => {
assertTypeInstanceOf(Integer, 'smallinteger'); assertTypeInstanceOf(Integer, 'smallinteger');
assertTypeInstanceOf(Integer, 'smallInteger'); assertTypeInstanceOf(Integer, 'smallInteger');
assertTypeInstanceOf(Integer, DataTypes.SMALLINT); assertTypeInstanceOf(Integer, DataTypes.SMALLINT);
assertTypeInstanceOf(Integer, DataTypes.SMALLINT({ assertTypeInstanceOf(
Integer,
DataTypes.SMALLINT({
length: 5, length: 5,
})); }),
);
}); });
it('shound be medium integer', () => { it('shound be medium integer', () => {
@ -102,9 +119,12 @@ describe('field types', () => {
assertTypeInstanceOf(Integer, 'MediumInteger'); assertTypeInstanceOf(Integer, 'MediumInteger');
assertTypeInstanceOf(Integer, 'MediumInteger'); assertTypeInstanceOf(Integer, 'MediumInteger');
assertTypeInstanceOf(Integer, DataTypes.MEDIUMINT); assertTypeInstanceOf(Integer, DataTypes.MEDIUMINT);
assertTypeInstanceOf(Integer, DataTypes.MEDIUMINT({ assertTypeInstanceOf(
Integer,
DataTypes.MEDIUMINT({
length: 5, length: 5,
})); }),
);
}); });
it('shound be big integer', () => { it('shound be big integer', () => {
@ -113,16 +133,22 @@ describe('field types', () => {
assertTypeInstanceOf(Integer, 'biginteger'); assertTypeInstanceOf(Integer, 'biginteger');
assertTypeInstanceOf(Integer, 'bigInteger'); assertTypeInstanceOf(Integer, 'bigInteger');
assertTypeInstanceOf(Integer, DataTypes.BIGINT); assertTypeInstanceOf(Integer, DataTypes.BIGINT);
assertTypeInstanceOf(Integer, DataTypes.BIGINT({ assertTypeInstanceOf(
Integer,
DataTypes.BIGINT({
length: 5, length: 5,
})); }),
);
}); });
it('shound be float', () => { it('shound be float', () => {
assertTypeInstanceOf(Float, 'float'); assertTypeInstanceOf(Float, 'float');
assertTypeInstanceOf(Float, DataTypes.FLOAT({ assertTypeInstanceOf(
Float,
DataTypes.FLOAT({
length: 5, length: 5,
})); }),
);
}); });
it('shound be double', () => { it('shound be double', () => {
@ -132,9 +158,12 @@ describe('field types', () => {
it('shound be real', () => { it('shound be real', () => {
assertTypeInstanceOf(Real, 'real'); assertTypeInstanceOf(Real, 'real');
assertTypeInstanceOf(Real, DataTypes.REAL({ assertTypeInstanceOf(
Real,
DataTypes.REAL({
length: 5, length: 5,
})); }),
);
}); });
it('shound be decimal', () => { it('shound be decimal', () => {
@ -151,9 +180,12 @@ describe('field types', () => {
it('shound be text', () => { it('shound be text', () => {
assertTypeInstanceOf(Text, 'text'); assertTypeInstanceOf(Text, 'text');
assertTypeInstanceOf(Text, DataTypes.TEXT); assertTypeInstanceOf(Text, DataTypes.TEXT);
assertTypeInstanceOf(Text, DataTypes.TEXT({ assertTypeInstanceOf(
Text,
DataTypes.TEXT({
length: 'long', length: 'long',
})); }),
);
}); });
it('shound be time', () => { it('shound be time', () => {
@ -185,6 +217,9 @@ describe('field types', () => {
}); });
it('shound be jsonb', () => { it('shound be jsonb', () => {
if (process.env.DB_DIALECT === 'sqlite') {
return;
}
assertTypeInstanceOf(Jsonb, 'jsonb'); assertTypeInstanceOf(Jsonb, 'jsonb');
assertTypeInstanceOf(Jsonb, DataTypes.JSONB); assertTypeInstanceOf(Jsonb, DataTypes.JSONB);
}); });
@ -273,7 +308,7 @@ describe('field types', () => {
name: 'password', name: 'password',
}, },
], ],
}) });
db.table({ db.table({
name: 'bars', name: 'bars',
tableName: 'formula_bars', tableName: 'formula_bars',
@ -281,9 +316,9 @@ describe('field types', () => {
{ {
type: 'string', type: 'string',
name: 'col2', name: 'col2',
} },
], ],
}) });
await db.sync({ force: true }); await db.sync({ force: true });
}); });
afterEach(async () => { afterEach(async () => {
@ -316,7 +351,7 @@ describe('field types', () => {
await formula.updateAssociations({ await formula.updateAssociations({
bar: { bar: {
col2: 'val2', col2: 'val2',
} },
}); });
const f = await Formula.findOne({ const f = await Formula.findOne({
where: { where: {
@ -324,7 +359,7 @@ describe('field types', () => {
}, },
include: { include: {
association: 'bar', association: 'bar',
} },
}); });
expect(f.reference1).toBe('val1'); expect(f.reference1).toBe('val1');
expect(f.reference2).toBe('val2'); expect(f.reference2).toBe('val2');

View File

@ -1,5 +1,7 @@
import Database from '../database'; import Database from '../database';
import { Dialect } from 'sequelize'; import { Dialect } from 'sequelize';
import path from 'path';
import { uid } from '../utils';
function getTestKey() { function getTestKey() {
const { id } = require.main; const { id } = require.main;
@ -9,36 +11,32 @@ function getTestKey() {
.replace(/src\/__tests__/g, '') .replace(/src\/__tests__/g, '')
.replace('.test.ts', '') .replace('.test.ts', '')
.replace(/[^\w]/g, '_'); .replace(/[^\w]/g, '_');
return key return key;
} }
const config = { let config: any = {
username: process.env.DB_USER, username: process.env.DB_USER,
password: process.env.DB_PASSWORD, password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE, database: process.env.DB_DATABASE,
host: process.env.DB_HOST, host: process.env.DB_HOST,
port: Number.parseInt(process.env.DB_PORT, 10), port: Number.parseInt(process.env.DB_PORT, 10),
dialect: process.env.DB_DIALECT as Dialect, dialect: process.env.DB_DIALECT as Dialect,
define: { logging: process.env.DB_LOG_SQL === 'on' ? console.log : false,
hooks: {
beforeCreate(model, options) {
},
},
},
logging: process.env.DB_LOG_SQL === 'on' ? console.log : false
}; };
console.log(config); if (process.env.DB_DIALECT === 'sqlite') {
config = {
dialect: process.env.DB_DIALECT as Dialect,
storage: path.resolve(__dirname, `./.db/${uid()}.sqlite`),
logging: process.env.DB_LOG_SQL === 'on' ? console.log : false,
};
}
export function getDatabase() { export function getDatabase() {
return new Database({ return new Database({
...config, ...config,
sync: { sync: {
force: true, force: true,
alter: {
drop: true,
}
}, },
hooks: { hooks: {
beforeDefine(model, options) { beforeDefine(model, options) {
@ -46,8 +44,10 @@ export function getDatabase() {
options.tableNamePrefix = `${getTestKey()}_`; options.tableNamePrefix = `${getTestKey()}_`;
// @ts-ignore // @ts-ignore
options.hookModelName = options.tableName; options.hookModelName = options.tableName;
options.tableName = `${getTestKey()}_${options.tableName || options.name.plural}`; options.tableName = `${getTestKey()}_${
options.tableName || options.name.plural
}`;
}, },
}, },
}); });
}; }

View File

@ -2,8 +2,6 @@ import Database from '../..';
import { getDatabase } from '..'; import { getDatabase } from '..';
import Model, { ModelCtor } from '../../model'; import Model, { ModelCtor } from '../../model';
let db: Database; let db: Database;
beforeEach(async () => { beforeEach(async () => {
@ -39,8 +37,8 @@ describe('model', () => {
scope: { scope: {
title: 'title1', title: 'title1',
}, },
} },
] ],
}); });
db.table({ db.table({
@ -51,7 +49,7 @@ describe('model', () => {
type: 'string', type: 'string',
name: 'name', name: 'name',
}, },
] ],
}); });
db.table({ db.table({
@ -87,7 +85,7 @@ describe('model', () => {
name: 'current_user_comments', name: 'current_user_comments',
target: 'comments', target: 'comments',
}, },
] ],
}); });
db.table({ db.table({
@ -98,7 +96,7 @@ describe('model', () => {
type: 'string', type: 'string',
name: 'name', name: 'name',
}, },
] ],
}); });
db.table({ db.table({
@ -131,8 +129,8 @@ describe('model', () => {
{ {
type: 'string', type: 'string',
name: 'content', name: 'content',
} },
] ],
}); });
db.table({ db.table({
@ -147,7 +145,7 @@ describe('model', () => {
{ {
type: 'hasMany', type: 'hasMany',
name: 'fields', name: 'fields',
} },
], ],
}); });
@ -161,7 +159,7 @@ describe('model', () => {
{ {
type: 'string', type: 'string',
name: 'name', name: 'name',
} },
], ],
}); });
@ -177,7 +175,7 @@ describe('model', () => {
type: 'hasMany', type: 'hasMany',
name: 'columns', name: 'columns',
sourceKey: 'name', sourceKey: 'name',
} },
], ],
}); });
@ -192,7 +190,7 @@ describe('model', () => {
{ {
type: 'string', type: 'string',
name: 'name', name: 'name',
} },
], ],
}); });
@ -208,7 +206,7 @@ describe('model', () => {
const user = await User.create(); const user = await User.create();
const post = await Post.create(); const post = await Post.create();
await post.updateAssociations({ await post.updateAssociations({
user: user.id user: user.id,
}); });
const authorizedPost = await Post.findByPk(post.id); const authorizedPost = await Post.findByPk(post.id);
@ -219,7 +217,7 @@ describe('model', () => {
const Post = db.getModel('posts'); const Post = db.getModel('posts');
const post = await Post.create(); const post = await Post.create();
await post.updateAssociations({ await post.updateAssociations({
user: {} user: {},
}); });
const authorizedPost = await Post.findByPk(post.id); const authorizedPost = await Post.findByPk(post.id);
@ -231,7 +229,7 @@ describe('model', () => {
const user = await User.create(); const user = await User.create();
const post = await Post.create(); const post = await Post.create();
await post.updateAssociations({ await post.updateAssociations({
user user,
}); });
const authorizedPost = await Post.findByPk(post.id); const authorizedPost = await Post.findByPk(post.id);
@ -244,10 +242,10 @@ describe('model', () => {
const user2 = await Post.create(); const user2 = await Post.create();
const post = await Post.create(); const post = await Post.create();
await post.updateAssociations({ await post.updateAssociations({
user: user1.id user: user1.id,
}); });
await post.updateAssociations({ await post.updateAssociations({
user: user2.id user: user2.id,
}); });
const authorizedPost = await Post.findByPk(post.id); const authorizedPost = await Post.findByPk(post.id);
@ -261,26 +259,26 @@ describe('model', () => {
const post = await Post.create(); const post = await Post.create();
const comments = await Comment.bulkCreate([{}, {}, {}, {}]); const comments = await Comment.bulkCreate([{}, {}, {}, {}]);
await post.updateAssociations({ await post.updateAssociations({
comments: comments.map(item => item.id) comments: comments.map((item) => item.id),
}); });
const postComments = await Comment.findAll({ const postComments = await Comment.findAll({
where: { post_id: post.id }, where: { post_id: post.id },
attributes: ['id'] attributes: ['id'],
}); });
expect(postComments.map(item => item.id)).toEqual([1, 2, 3, 4]); expect(postComments.map((item) => item.id)).toEqual([1, 2, 3, 4]);
}); });
it('update with new object', async () => { it('update with new object', async () => {
const [Post, Comment] = db.getModels(['posts', 'comments']); const [Post, Comment] = db.getModels(['posts', 'comments']);
const post = await Post.create(); const post = await Post.create();
await post.updateAssociations({ await post.updateAssociations({
comments: [{}, {}, {}, {}] comments: [{}, {}, {}, {}],
}); });
const postCommentIds = await Comment.findAll({ const postCommentIds = await Comment.findAll({
where: { post_id: post.id }, where: { post_id: post.id },
attributes: ['id'] attributes: ['id'],
}); });
expect(postCommentIds.map(item => item.id)).toEqual([1, 2, 3, 4]); expect(postCommentIds.map((item) => item.id)).toEqual([1, 2, 3, 4]);
}); });
it('update with new model', async () => { it('update with new model', async () => {
@ -288,13 +286,13 @@ describe('model', () => {
const post = await Post.create(); const post = await Post.create();
const comments = await Comment.bulkCreate([{}, {}, {}, {}]); const comments = await Comment.bulkCreate([{}, {}, {}, {}]);
await post.updateAssociations({ await post.updateAssociations({
comments comments,
}); });
const postCommentIds = await Comment.findAll({ const postCommentIds = await Comment.findAll({
where: { post_id: post.id }, where: { post_id: post.id },
attributes: ['id'] attributes: ['id'],
}); });
expect(postCommentIds.map(item => item.id)).toEqual([1, 2, 3, 4]); expect(postCommentIds.map((item) => item.id)).toEqual([1, 2, 3, 4]);
}); });
it('update with exist rows/primaryKeys', async () => { it('update with exist rows/primaryKeys', async () => {
@ -302,19 +300,19 @@ describe('model', () => {
const post = await Post.create(); const post = await Post.create();
const comments = await Comment.bulkCreate([{}, {}, {}, {}]); const comments = await Comment.bulkCreate([{}, {}, {}, {}]);
await post.updateAssociations({ await post.updateAssociations({
comments comments,
}); });
await post.updateAssociations({ await post.updateAssociations({
comments comments,
}); });
await post.updateAssociations({ await post.updateAssociations({
comments: comments.map(item => item.id) comments: comments.map((item) => item.id),
}); });
const postCommentIds = await Comment.findAll({ const postCommentIds = await Comment.findAll({
where: { post_id: post.id }, where: { post_id: post.id },
attributes: ['id'] attributes: ['id'],
}); });
expect(postCommentIds.map(item => item.id)).toEqual([1, 2, 3, 4]); expect(postCommentIds.map((item) => item.id)).toEqual([1, 2, 3, 4]);
}); });
it('update with exist objects', async () => { it('update with exist objects', async () => {
@ -322,23 +320,25 @@ describe('model', () => {
const post = await Post.create(); const post = await Post.create();
const comments = await Comment.bulkCreate([{}, {}, {}, {}]); const comments = await Comment.bulkCreate([{}, {}, {}, {}]);
await post.updateAssociations({ await post.updateAssociations({
comments comments,
}); });
await post.updateAssociations({ await post.updateAssociations({
comments: comments.map(item => ({ comments: comments.map((item) => ({
...item.get(), ...item.get(),
content: `content${item.id}` content: `content${item.id}`,
})) })),
}); });
const postComments = await Comment.findAll({ const postComments = await Comment.findAll({
where: { post_id: post.id }, where: { post_id: post.id },
attributes: ['id', 'content'] attributes: ['id', 'content'],
}); });
expect(postComments.map(({ id, content }) => ({ id, content }))).toEqual([ expect(
postComments.map(({ id, content }) => ({ id, content })),
).toEqual([
{ id: 1, content: 'content1' }, { id: 1, content: 'content1' },
{ id: 2, content: 'content2' }, { id: 2, content: 'content2' },
{ id: 3, content: 'content3' }, { id: 3, content: 'content3' },
{ id: 4, content: 'content4' } { id: 4, content: 'content4' },
]); ]);
}); });
@ -348,39 +348,43 @@ describe('model', () => {
const post2 = await Post.create(); const post2 = await Post.create();
const comments = await Comment.bulkCreate([{}, {}, {}, {}]); const comments = await Comment.bulkCreate([{}, {}, {}, {}]);
await post.updateAssociations({ await post.updateAssociations({
comments comments,
}); });
const postComments = await Comment.findAll({ const postComments = await Comment.findAll({
where: { post_id: post.id } where: { post_id: post.id },
}); });
expect(postComments.map(({ id, post_id }) => ({ id, post_id }))).toEqual([ expect(
postComments.map(({ id, post_id }) => ({ id, post_id })),
).toEqual([
{ id: 1, post_id: post.id }, { id: 1, post_id: post.id },
{ id: 2, post_id: post.id }, { id: 2, post_id: post.id },
{ id: 3, post_id: post.id }, { id: 3, post_id: post.id },
{ id: 4, post_id: post.id } { id: 4, post_id: post.id },
]); ]);
await post2.updateAssociations({ await post2.updateAssociations({
comments: postComments.map(item => ({ comments: postComments.map((item) => ({
...item.get(), ...item.get(),
content: `content${item.id}` content: `content${item.id}`,
})) })),
}); });
const updatedComments = await Comment.findAll(); const updatedComments = await Comment.findAll();
const post1CommentsCount = await Comment.count({ const post1CommentsCount = await Comment.count({
where: { post_id: post.id } where: { post_id: post.id },
}); });
expect(post1CommentsCount).toBe(0); expect(post1CommentsCount).toBe(0);
const post2Comments = await Comment.findAll({ const post2Comments = await Comment.findAll({
where: { post_id: post2.id }, where: { post_id: post2.id },
attributes: ['id', 'content'] attributes: ['id', 'content'],
}); });
expect(post2Comments.map(({ id, content }) => ({ id, content }))).toEqual([ expect(
post2Comments.map(({ id, content }) => ({ id, content })),
).toEqual([
{ id: 1, content: 'content1' }, { id: 1, content: 'content1' },
{ id: 2, content: 'content2' }, { id: 2, content: 'content2' },
{ id: 3, content: 'content3' }, { id: 3, content: 'content3' },
{ id: 4, content: 'content4' } { id: 4, content: 'content4' },
]); ]);
}); });
@ -389,17 +393,17 @@ describe('model', () => {
const post = await Post.create(); const post = await Post.create();
const comments = await Comment.bulkCreate([{}, {}, {}, {}]); const comments = await Comment.bulkCreate([{}, {}, {}, {}]);
await post.updateAssociations({ await post.updateAssociations({
comments comments,
}); });
await post.updateAssociations({ await post.updateAssociations({
comments: comments comments: comments
.filter(({ id }) => Boolean(id % 2)) .filter(({ id }) => Boolean(id % 2))
.concat(...[await Comment.create()]) .concat(...[await Comment.create()]),
}); });
const postComments = await Comment.findAll({ const postComments = await Comment.findAll({
where: { post_id: post.id }, where: { post_id: post.id },
attributes: ['id'] attributes: ['id'],
}); });
expect(postComments.map(({ id }) => id)).toEqual([1, 3, 5]); expect(postComments.map(({ id }) => id)).toEqual([1, 3, 5]);
}); });
@ -407,37 +411,47 @@ describe('model', () => {
describe('belongsToMany', () => { describe('belongsToMany', () => {
it('update with primary key', async () => { it('update with primary key', async () => {
const [Post, Tag, PostTag] = db.getModels(['posts', 'tags', 'posts_tags']); const [Post, Tag, PostTag] = db.getModels([
'posts',
'tags',
'posts_tags',
]);
const post = await Post.create(); const post = await Post.create();
const tags = await Tag.bulkCreate([{}, {}, {}, {}]); const tags = await Tag.bulkCreate([{}, {}, {}, {}]);
await post.updateAssociations({ await post.updateAssociations({
tags: tags.map(item => item.id) tags: tags.map((item) => item.id),
}); });
const tagged = await PostTag.findAll({ const tagged = await PostTag.findAll({
where: { post_id: post.id }, where: { post_id: post.id },
attributes: ['tag_id'] attributes: ['tag_id'],
}); });
expect(tagged.map(item => item.tag_id)).toEqual([1, 2, 3, 4]); expect(tagged.map((item) => item.tag_id)).toEqual([1, 2, 3, 4]);
}); });
it('update with exist rows/primaryKeys', async () => { it('update with exist rows/primaryKeys', async () => {
const [Post, Tag, PostTag] = db.getModels(['posts', 'tags', 'posts_tags']); const [Post, Tag, PostTag] = db.getModels([
'posts',
'tags',
'posts_tags',
]);
const post = await Post.create(); const post = await Post.create();
const tags = await Tag.bulkCreate([{}, {}, {}, {}]); const tags = await Tag.bulkCreate([{}, {}, {}, {}]);
await post.updateAssociations({ await post.updateAssociations({
tags: tags.map(item => item.id) tags: tags.map((item) => item.id),
}); });
await post.updateAssociations({ await post.updateAssociations({
tags: tags.map(item => item.id) tags: tags.map((item) => item.id),
}); });
await post.updateAssociations({ await post.updateAssociations({
tags tags,
}); });
const tagged = await PostTag.findAll({ const tagged = await PostTag.findAll({
where: { post_id: post.id }, where: { post_id: post.id },
attributes: ['tag_id', 'post_id'] attributes: ['tag_id', 'post_id'],
}); });
expect(tagged.map(({ post_id, tag_id }) => ({ post_id, tag_id }))).toEqual([ expect(
tagged.map(({ post_id, tag_id }) => ({ post_id, tag_id })),
).toEqual([
{ tag_id: 1, post_id: 1 }, { tag_id: 1, post_id: 1 },
{ tag_id: 2, post_id: 1 }, { tag_id: 2, post_id: 1 },
{ tag_id: 3, post_id: 1 }, { tag_id: 3, post_id: 1 },
@ -446,35 +460,47 @@ describe('model', () => {
}); });
it('update with exist rows/primaryKeys and new objects', async () => { it('update with exist rows/primaryKeys and new objects', async () => {
const [Post, Tag, PostTag] = db.getModels(['posts', 'tags', 'posts_tags']); const [Post, Tag, PostTag] = db.getModels([
'posts',
'tags',
'posts_tags',
]);
const post = await Post.create(); const post = await Post.create();
const tags = await Tag.bulkCreate([{}, {}, {}, {}]); const tags = await Tag.bulkCreate([{}, {}, {}, {}]);
await post.updateAssociations({ await post.updateAssociations({
tags: tags.map(item => item.id) tags: tags.map((item) => item.id),
}); });
await post.updateAssociations({ await post.updateAssociations({
tags: tags.filter(({ id }) => Boolean(id % 2)).concat(await Tag.create({})) tags: tags
.filter(({ id }) => Boolean(id % 2))
.concat(await Tag.create({})),
}); });
const tagged = await PostTag.findAll({ const tagged = await PostTag.findAll({
where: { post_id: post.id }, where: { post_id: post.id },
attributes: ['tag_id'] attributes: ['tag_id'],
}); });
expect(tagged.map(({ tag_id }) => tag_id)).toEqual([1, 3, 5]); expect(tagged.map(({ tag_id }) => tag_id)).toEqual([1, 3, 5]);
}); });
it('update other with exist rows/primaryKeys', async () => { it('update other with exist rows/primaryKeys', async () => {
const [Post, Tag, PostTag] = db.getModels(['posts', 'tags', 'posts_tags']); const [Post, Tag, PostTag] = db.getModels([
'posts',
'tags',
'posts_tags',
]);
const post = await Post.create(); const post = await Post.create();
const post2 = await Post.create(); const post2 = await Post.create();
const tags = await Tag.bulkCreate([{}, {}, {}, {}]); const tags = await Tag.bulkCreate([{}, {}, {}, {}]);
await post.updateAssociations({ await post.updateAssociations({
tags: tags.map(item => item.id) tags: tags.map((item) => item.id),
}); });
await post2.updateAssociations({ await post2.updateAssociations({
tags tags,
}); });
const tagged = await PostTag.findAll(); const tagged = await PostTag.findAll();
expect(tagged.map(({ post_id, tag_id }) => ({ post_id, tag_id }))).toEqual([ expect(
tagged.map(({ post_id, tag_id }) => ({ post_id, tag_id })),
).toEqual([
{ tag_id: 1, post_id: 1 }, { tag_id: 1, post_id: 1 },
{ tag_id: 2, post_id: 1 }, { tag_id: 2, post_id: 1 },
{ tag_id: 3, post_id: 1 }, { tag_id: 3, post_id: 1 },
@ -492,17 +518,20 @@ describe('model', () => {
const post = await Post.create(); const post = await Post.create();
const tag = await Tag.create(); const tag = await Tag.create();
await post.updateAssociations({ await post.updateAssociations({
tags: [{ tags: [
{
name: 'xxx', name: 'xxx',
posts_tags: { posts_tags: {
name: 'name134', name: 'name134',
} },
}, { },
{
id: tag.id, id: tag.id,
posts_tags: { posts_tags: {
name: 'name234', name: 'name234',
} },
}], },
],
}); });
const PostTag = db.getModel('posts_tags'); const PostTag = db.getModel('posts_tags');
const [t1, t2] = await PostTag.findAll({ const [t1, t2] = await PostTag.findAll({
@ -518,7 +547,11 @@ describe('model', () => {
describe('scope', () => { describe('scope', () => {
it('scope', async () => { it('scope', async () => {
const [User, Post, Comment] = db.getModels(['users', 'posts', 'comments']); const [User, Post, Comment] = db.getModels([
'users',
'posts',
'comments',
]);
const user1 = await User.create(); const user1 = await User.create();
const user2 = await User.create(); const user2 = await User.create();
const user3 = await User.create(); const user3 = await User.create();
@ -565,8 +598,8 @@ describe('model', () => {
return { return {
where: { where: {
name: name, name: name,
} },
} };
}); });
const [User, Post] = db.getModels(['users', 'posts']); const [User, Post] = db.getModels(['users', 'posts']);
@ -589,29 +622,22 @@ describe('model', () => {
posts: post, posts: post,
}); });
await post.updateAssociations({ await post.updateAssociations({
tags: [ tags: [{ name: 'tag1' }, { name: 'tag2' }, { name: 'tag3' }],
{ name: 'tag1' },
{ name: 'tag2' },
{ name: 'tag3' },
],
}); });
// where & include // where & include
const options = Post.parseApiJson({ const options = Post.parseApiJson({
filter: { filter: {
title: 'title112233', title: 'title112233',
user: { // belongsTo user: {
// belongsTo
name: 'name112233', name: 'name112233',
}, },
tags: { // belongsToMany tags: {
// belongsToMany
scopeName: 'tag3', scopeName: 'tag3',
}, },
}, },
fields: [ fields: ['title', 'tags_count', 'tags.name', 'user.name'],
'title',
'tags_count',
'tags.name',
'user.name'
],
sort: '-tags_count,tags.name,user.posts_count', sort: '-tags_count,tags.name,user.posts_count',
context: { context: {
scopeName: 'tag3', scopeName: 'tag3',
@ -631,7 +657,7 @@ describe('model', () => {
// console.log(JSON.stringify(rows[0].toJSON(), null, 2)); // console.log(JSON.stringify(rows[0].toJSON(), null, 2));
rows.forEach(row => { rows.forEach((row) => {
// expect(row.toJSON()).toEqual({ title: 'title112233', 'tags_count': 3, user: { name: 'name112233', posts_count: 1 } }); // expect(row.toJSON()).toEqual({ title: 'title112233', 'tags_count': 3, user: { name: 'name112233', posts_count: 1 } });
expect(row.get('title')).toBe('title112233'); expect(row.get('title')).toBe('title112233');
expect(row.user.get('name')).toBe('name112233'); expect(row.user.get('name')).toBe('name112233');
@ -694,7 +720,7 @@ describe('model', () => {
include: [ include: [
User.withCountAttribute({ User.withCountAttribute({
association: 'posts', association: 'posts',
alias: 'posts2_count' alias: 'posts2_count',
}), }),
], ],
}, },
@ -736,7 +762,9 @@ describe('model', () => {
include: [ include: [
{ {
association: 'user', association: 'user',
attributes: ['id', 'name', attributes: [
'id',
'name',
User.withCountAttribute({ User.withCountAttribute({
sourceAlias: 'user', sourceAlias: 'user',
association: 'posts', association: 'posts',
@ -752,7 +780,7 @@ describe('model', () => {
expect(post.get('tags_count')).toBe(5); expect(post.get('tags_count')).toBe(5);
expect(post.get('tags_name1_count')).toBe(1); expect(post.get('tags_name1_count')).toBe(1);
expect(post.user.get('posts_count')).toBe(1); expect(post.user.get('posts_count')).toBe(1);
post.tags.forEach(tag => { post.tags.forEach((tag) => {
expect(tag.get('posts_count')).toBe(1); expect(tag.get('posts_count')).toBe(1);
}); });
}); });
@ -904,9 +932,7 @@ describe('model', () => {
name: 'examples', name: 'examples',
}); });
await table.updateAssociations({ await table.updateAssociations({
fields: [ fields: [{ name: 'name' }],
{ name: 'name' },
]
}); });
const field = await Field.findOne({ const field = await Field.findOne({
where: { where: {
@ -924,9 +950,7 @@ describe('model', () => {
name: 'examples', name: 'examples',
}); });
await row.updateAssociations({ await row.updateAssociations({
columns: [ columns: [{ name: 'name' }],
{ name: 'name' },
]
}); });
const column = await Column.findOne({ const column = await Column.findOne({
where: { where: {
@ -950,7 +974,7 @@ describe('model', () => {
id: field.id, id: field.id,
name: 'nam1234', name: 'nam1234',
}, },
] ],
}); });
const f = await Field.findOne({ const f = await Field.findOne({
@ -973,7 +997,6 @@ describe('model', () => {
}); });
describe('blongsTo', () => { describe('blongsTo', () => {
it('shoud associated id when association is integer', async () => { it('shoud associated id when association is integer', async () => {
const [User, Post] = db.getModels(['users', 'posts']); const [User, Post] = db.getModels(['users', 'posts']);
const user = await User.create(); const user = await User.create();
@ -1143,7 +1166,7 @@ describe('model', () => {
const post = await Post.create(); const post = await Post.create();
await post.updateAssociations({ await post.updateAssociations({
tags: { tags: {
name: 'tag1' name: 'tag1',
}, },
}); });
const count = await post.countTags(); const count = await post.countTags();
@ -1156,10 +1179,10 @@ describe('model', () => {
await post.updateAssociations({ await post.updateAssociations({
tags: [ tags: [
{ {
name: 'tag2' name: 'tag2',
}, },
{ {
name: 'tag3' name: 'tag3',
}, },
], ],
}); });
@ -1239,9 +1262,11 @@ describe('belongsToMany', () => {
}); });
it('update with new object', async () => { it('update with new object', async () => {
await post.updateAssociations({ await post.updateAssociations({
tags: [{ tags: [
{
name: 'tag3', name: 'tag3',
}], },
],
}); });
expect(await post.countTags()).toBe(1); expect(await post.countTags()).toBe(1);
}); });

View File

@ -29,6 +29,7 @@ afterEach(async () => {
describe('op', () => { describe('op', () => {
it('test', async () => { it('test', async () => {
if ((process.env.DB_DIALECT = 'sqlite')) return;
const Test = db.getModel('tests'); const Test = db.getModel('tests');
await Test.bulkCreate([ await Test.bulkCreate([
{ {
@ -42,7 +43,7 @@ describe('op', () => {
}, },
{ {
arr: ['dd'], arr: ['dd'],
} },
]); ]);
const options = Test.parseApiJson({ const options = Test.parseApiJson({
filter: { filter: {

View File

@ -168,7 +168,7 @@ type HookType =
const hookType = this._getHookType(event); const hookType = this._getHookType(event);
if (hookType) { if (hookType) {
const state = this.hookTypes.get(hookType); const state = this.hookTypes.get(hookType);
console.log('sequelize.addHook', event, hookType)
this.sequelize.addHook(hookType, async (...args: any[]) => { this.sequelize.addHook(hookType, async (...args: any[]) => {
let modelName: string; let modelName: string;
switch (state) { switch (state) {

View File

@ -1,5 +1,10 @@
import { import {
Model as SequelizeModel, Op, Sequelize, ProjectionAlias, Utils, SaveOptions Model as SequelizeModel,
Op,
Sequelize,
ProjectionAlias,
Utils,
SaveOptions,
} from 'sequelize'; } from 'sequelize';
import Database from './database'; import Database from './database';
import { import {
@ -12,7 +17,6 @@ import {
import { toInclude } from './utils'; import { toInclude } from './utils';
export interface ApiJsonOptions { export interface ApiJsonOptions {
/** /**
* *
* *
@ -31,10 +35,13 @@ export interface ApiJsonOptions {
* appends: ['association_count'], * appends: ['association_count'],
* } * }
*/ */
fields?: string[] | { fields?:
| string[]
| {
only?: string[]; only?: string[];
appends?: string[]; appends?: string[];
} | { }
| {
except?: string[]; except?: string[];
appends?: string[]; appends?: string[];
}; };
@ -100,7 +107,6 @@ export interface ApiJsonOptions {
} }
export interface WithCountAttributeOptions { export interface WithCountAttributeOptions {
/** /**
* *
*/ */
@ -148,7 +154,6 @@ export interface UpdateAssociationOptions extends SaveOptions {
*/ */
// @ts-ignore // @ts-ignore
export abstract class Model extends SequelizeModel { export abstract class Model extends SequelizeModel {
/** /**
* ts * ts
*/ */
@ -176,12 +181,20 @@ export abstract class Model extends SequelizeModel {
* *
* @param options * @param options
*/ */
static withCountAttribute(options?: string | WithCountAttributeOptions): (string | ProjectionAlias) { static withCountAttribute(
options?: string | WithCountAttributeOptions,
): string | ProjectionAlias {
if (typeof options === 'string') { if (typeof options === 'string') {
options = { association: options }; options = { association: options };
} }
const { sourceAlias, association, where = {}, alias, ...restOptions } = options; const {
sourceAlias,
association,
where = {},
alias,
...restOptions
} = options;
const associator = this.associations[association]; const associator = this.associations[association];
const table = this.database.getTable(this.name); const table = this.database.getTable(this.name);
const field = table.getField(association); const field = table.getField(association);
@ -193,17 +206,20 @@ export abstract class Model extends SequelizeModel {
}; };
} else if (associator.associationType === 'BelongsToMany') { } else if (associator.associationType === 'BelongsToMany') {
where[targetKey] = { where[targetKey] = {
// @ts-ignore [Op.in]: Sequelize.literal(
[Op.in]: Sequelize.literal(`(${associator.through.model.selectQuery({ `(${(associator as any).through.model.selectQuery({
attributes: [otherKey], attributes: [otherKey],
where: { where: {
[foreignKey]: { [foreignKey]: {
[Op.eq]: Sequelize.col(`${sourceAlias || this.name}.${sourceKey}`), [Op.eq]: Sequelize.col(
`${sourceAlias || this.name}.${sourceKey}`,
),
}, },
// @ts-ignore // @ts-ignore
...(associator.through.scope || {}), ...(associator.through.scope || {}),
}, },
})})`), })})`,
),
}; };
} }
@ -221,14 +237,16 @@ export abstract class Model extends SequelizeModel {
attributes: [[Sequelize.literal(countLiteral), 'count']], attributes: [[Sequelize.literal(countLiteral), 'count']],
where: { where: {
// @ts-ignore // @ts-ignore
...where, ...(associator.scope || {}), ...where,
...((associator as any).scope || {}),
}, },
})})` })})`,
), ),
alias || Utils.underscoredIf(`${association}Count`, this.options.underscored), alias ||
Utils.underscoredIf(`${association}Count`, this.options.underscored),
].filter(Boolean); ].filter(Boolean);
return attribute as unknown as ProjectionAlias; return (attribute as unknown) as ProjectionAlias;
} }
/** /**
@ -238,24 +256,28 @@ export abstract class Model extends SequelizeModel {
*/ */
static selectQuery(options = {}): string { static selectQuery(options = {}): string {
// @ts-ignore // @ts-ignore
return this.queryGenerator.selectQuery( return this.queryGenerator
this.getTableName(), .selectQuery(this.getTableName(), options, this)
options, .replace(/;$/, '');
this,
).replace(/;$/, '');
} }
static parseApiJson(options: ApiJsonOptions) { static parseApiJson(options: ApiJsonOptions) {
const { fields, filter, sort, context, page, perPage } = options; const { fields, filter, sort, context, page, perPage } = options;
const data = toInclude({ fields, filter, sort }, { const data = toInclude(
{ fields, filter, sort },
{
model: this, model: this,
associations: this.associations, associations: this.associations,
dialect: this.sequelize.getDialect(), dialect: this.sequelize.getDialect(),
ctx: context, ctx: context,
database: this.database, database: this.database,
}); },
);
if (page || perPage) { if (page || perPage) {
data.limit = perPage === -1 ? MAX_LIMIT : Math.min(perPage || DEFAULT_LIMIT, MAX_LIMIT); data.limit =
perPage === -1
? MAX_LIMIT
: Math.min(perPage || DEFAULT_LIMIT, MAX_LIMIT);
data.offset = data.limit * (page > 0 ? page - 1 : DEFAULT_OFFSET); data.offset = data.limit * (page > 0 ? page - 1 : DEFAULT_OFFSET);
} }
if (data.attributes && data.attributes.length === 0) { if (data.attributes && data.attributes.length === 0) {
@ -269,9 +291,10 @@ export abstract class Model extends SequelizeModel {
const Model = table.getModel(); const Model = table.getModel();
const associations = table.getAssociations(); const associations = table.getAssociations();
const where = {}; const where = {};
scope.forEach(col => { scope.forEach((col) => {
const association = associations.get(col); const association = associations.get(col);
const dataKey = association && association instanceof BELONGSTO const dataKey =
association && association instanceof BELONGSTO
? association.options.foreignKey ? association.options.foreignKey
: col; : col;
if (!Model.rawAttributes[dataKey]) { if (!Model.rawAttributes[dataKey]) {
@ -285,7 +308,11 @@ export abstract class Model extends SequelizeModel {
return where; return where;
} }
async updateSingleAssociation(key: string, data: any, options: UpdateAssociationOptions = {}) { async updateSingleAssociation(
key: string,
data: any,
options: UpdateAssociationOptions = {},
) {
const { const {
fields, fields,
transaction = await this.sequelize.transaction(), transaction = await this.sequelize.transaction(),
@ -302,11 +329,16 @@ export abstract class Model extends SequelizeModel {
return; return;
} }
if (typeof data === 'number' || typeof data === 'string' || data instanceof SequelizeModel) { if (
typeof data === 'number' ||
typeof data === 'string' ||
data instanceof SequelizeModel
) {
await this[accessors.set](data, opts); await this[accessors.set](data, opts);
} else if (typeof data === 'object') { } else if (typeof data === 'object') {
const Target = association.getTargetModel(); const Target = association.getTargetModel();
const targetAttribute = association instanceof BELONGSTO const targetAttribute =
association instanceof BELONGSTO
? association.options.targetKey ? association.options.targetKey
: association.options.sourceKey; : association.options.sourceKey;
if (data[targetAttribute]) { if (data[targetAttribute]) {
@ -315,7 +347,7 @@ export abstract class Model extends SequelizeModel {
where: { where: {
[targetAttribute]: data[targetAttribute], [targetAttribute]: data[targetAttribute],
}, },
transaction transaction,
}); });
if (target) { if (target) {
await this[accessors.set](data[targetAttribute], opts); await this[accessors.set](data[targetAttribute], opts);
@ -337,7 +369,11 @@ export abstract class Model extends SequelizeModel {
} }
} }
async updateMultipleAssociation(associationName: string, data: any, options: UpdateAssociationOptions = {}) { async updateMultipleAssociation(
associationName: string,
data: any,
options: UpdateAssociationOptions = {},
) {
const items = Array.isArray(data) ? data : data == null ? [] : [data]; const items = Array.isArray(data) ? data : data == null ? [] : [data];
const { const {
@ -371,7 +407,7 @@ export abstract class Model extends SequelizeModel {
const toUpsertObjects = []; const toUpsertObjects = [];
// 遍历所有值成员准备数据 // 遍历所有值成员准备数据
items.forEach(item => { items.forEach((item) => {
if (item instanceof SequelizeModel) { if (item instanceof SequelizeModel) {
if (targetKeyIsPk) { if (targetKeyIsPk) {
toSetPks.add(item.getDataValue(targetPk)); toSetPks.add(item.getDataValue(targetPk));
@ -381,14 +417,18 @@ export abstract class Model extends SequelizeModel {
return; return;
} }
if (typeof item === 'number' || typeof item === 'string') { if (typeof item === 'number' || typeof item === 'string') {
let targetKeyType = getDataTypeKey(Target.rawAttributes[targetKey].type).toLocaleLowerCase(); let targetKeyType = getDataTypeKey(
Target.rawAttributes[targetKey].type,
).toLocaleLowerCase();
if (targetKeyType === 'integer') { if (targetKeyType === 'integer') {
targetKeyType = 'number'; targetKeyType = 'number';
} }
// 如果传值类型与之前在 Model 上定义的 targetKey 不同,则报错。 // 如果传值类型与之前在 Model 上定义的 targetKey 不同,则报错。
// 不应兼容定义的 targetKey 不是 primaryKey 却传了 primaryKey 的值的情况。 // 不应兼容定义的 targetKey 不是 primaryKey 却传了 primaryKey 的值的情况。
if (typeof item !== targetKeyType) { if (typeof item !== targetKeyType) {
throw new Error(`target key type [${typeof item}] does not match to [${targetKeyType}]`); throw new Error(
`target key type [${typeof item}] does not match to [${targetKeyType}]`,
);
} }
if (targetKeyIsPk) { if (targetKeyIsPk) {
toSetPks.add(item); toSetPks.add(item);
@ -404,31 +444,35 @@ export abstract class Model extends SequelizeModel {
/* 仅传关联键处理开始 */ /* 仅传关联键处理开始 */
// 查找已存在的数据 // 查找已存在的数据
const byPkExistItems = toSetPks.size ? await Target.findAll({ const byPkExistItems = toSetPks.size
? await Target.findAll({
...opts, ...opts,
// @ts-ignore // @ts-ignore
where: { where: {
[targetPk]: { [targetPk]: {
[Op.in]: Array.from(toSetPks) [Op.in]: Array.from(toSetPks),
}
}, },
attributes: [targetPk] },
}) : []; attributes: [targetPk],
byPkExistItems.forEach(item => { })
: [];
byPkExistItems.forEach((item) => {
toSetItems.add(item); toSetItems.add(item);
}); });
const byUkExistItems = toSetUks.size ? await Target.findAll({ const byUkExistItems = toSetUks.size
? await Target.findAll({
...opts, ...opts,
// @ts-ignore // @ts-ignore
where: { where: {
[targetKey]: { [targetKey]: {
[Op.in]: Array.from(toSetUks) [Op.in]: Array.from(toSetUks),
}
}, },
attributes: [targetPk, targetKey] },
}) : []; attributes: [targetPk, targetKey],
byUkExistItems.forEach(item => { })
: [];
byUkExistItems.forEach((item) => {
toSetItems.add(item); toSetItems.add(item);
}); });
/* 仅传关联键处理结束 */ /* 仅传关联键处理结束 */
@ -458,7 +502,7 @@ export abstract class Model extends SequelizeModel {
if (association instanceof BELONGSTOMANY) { if (association instanceof BELONGSTOMANY) {
belongsToManyList.push({ belongsToManyList.push({
item, item,
target target,
}); });
} }
@ -474,7 +518,6 @@ export abstract class Model extends SequelizeModel {
const ThroughModel = (association as BELONGSTOMANY).getThroughModel(); const ThroughModel = (association as BELONGSTOMANY).getThroughModel();
const throughName = (association as BELONGSTOMANY).getThroughName(); const throughName = (association as BELONGSTOMANY).getThroughName();
for (const { item, target } of belongsToManyList) { for (const { item, target } of belongsToManyList) {
const throughValues = item[throughName]; const throughValues = item[throughName];
if (throughValues && typeof throughValues === 'object') { if (throughValues && typeof throughValues === 'object') {
@ -484,7 +527,7 @@ export abstract class Model extends SequelizeModel {
[foreignKey]: this.get(sourceKey), [foreignKey]: this.get(sourceKey),
[otherKey]: target.get(targetKey), [otherKey]: target.get(targetKey),
}, },
transaction transaction,
}); });
await through.update(throughValues, opts); await through.update(throughValues, opts);
// TODO有 BUG未知 // TODO有 BUG未知
@ -498,7 +541,11 @@ export abstract class Model extends SequelizeModel {
} }
} }
async updateAssociation(key: string, data: any, options: UpdateAssociationOptions = {}) { async updateAssociation(
key: string,
data: any,
options: UpdateAssociationOptions = {},
) {
const table = this.database.getTable(this.constructor.name); const table = this.database.getTable(this.constructor.name);
const association = table.getAssociations().get(key); const association = table.getAssociations().get(key);
switch (true) { switch (true) {
@ -526,7 +573,7 @@ export abstract class Model extends SequelizeModel {
} }
await this.updateAssociation(key, data[key], { await this.updateAssociation(key, data[key], {
...options, ...options,
transaction transaction,
}); });
} }
@ -544,6 +591,8 @@ export abstract class Model extends SequelizeModel {
/** /**
* ModelCtor Model * ModelCtor Model
*/ */
export type ModelCtor<M extends Model> = typeof Model & { new(): M } & { [key: string]: any }; export type ModelCtor<M extends Model> = typeof Model & { new (): M } & {
[key: string]: any;
};
export default Model; export default Model;

View File

@ -53,36 +53,58 @@ op.set('$isFalsy', () => ({
// 字符串 // 字符串
// 包含:指对应字段的值包含某个子串 // 包含:指对应字段的值包含某个子串
op.set('$includes', (value: string) => ({ [Op.iLike]: `%${value}%` })); op.set('$includes', (value: string, { dialect }) => ({
[dialect === 'postgres' ? Op.iLike : Op.like]: `%${value}%`,
}));
// 不包含:指对应字段的值不包含某个子串(慎用:性能问题) // 不包含:指对应字段的值不包含某个子串(慎用:性能问题)
op.set('$notIncludes', (value: string) => ({ [Op.notILike]: `%${value}%` })); op.set('$notIncludes', (value: string, { dialect }) => ({
[dialect === 'postgres' ? Op.notILike : Op.notLike]: `%${value}%`,
}));
// 以之起始 // 以之起始
op.set('$startsWith', (value: string) => ({ [Op.iLike]: `${value}%` })); op.set('$startsWith', (value: string, { dialect }) => ({
[dialect === 'postgres' ? Op.iLike : Op.like]: `${value}%`,
}));
// 不以之起始 // 不以之起始
op.set('$notStartsWith', (value: string) => ({ [Op.notILike]: `${value}%` })); op.set('$notStartsWith', (value: string, { dialect }) => ({
[dialect === 'postgres' ? Op.notILike : Op.notLike]: `${value}%`,
}));
// 以之结束 // 以之结束
op.set('$endsWith', (value: string) => ({ [Op.iLike]: `%${value}` })); op.set('$endsWith', (value: string, { dialect }) => ({
[dialect === 'postgres' ? Op.iLike : Op.like]: `%${value}`,
}));
// 不以之结束 // 不以之结束
op.set('$notEndsWith', (value: string) => ({ [Op.notILike]: `%${value}` })); op.set('$notEndsWith', (value: string, { dialect }) => ({
[dialect === 'postgres' ? Op.notILike : Op.notLike]: `%${value}`,
}));
// 仅日期 // 仅日期
// 在某日 // 在某日
op.set('$dateOn', (value: string) => ({ [Op.and]: [{ [Op.gte]: stringToDate(value) }, { [Op.lt]: getNextDay(value) }] })); op.set('$dateOn', (value: string) => ({
[Op.and]: [{ [Op.gte]: stringToDate(value) }, { [Op.lt]: getNextDay(value) }],
}));
// 不在某日 // 不在某日
op.set('$dateNotOn', (value: string) => ({ [Op.or]: [{ [Op.lt]: stringToDate(value) }, { [Op.gte]: getNextDay(value) }] })); op.set('$dateNotOn', (value: string) => ({
[Op.or]: [{ [Op.lt]: stringToDate(value) }, { [Op.gte]: getNextDay(value) }],
}));
// 某日前 // 某日前
op.set('$dateBefore', (value: string) => ({ [Op.lt]: stringToDate(value) })); op.set('$dateBefore', (value: string) => ({ [Op.lt]: stringToDate(value) }));
// 某日后 // 某日后
op.set('$dateAfter', (value: string) => ({ [Op.gte]: getNextDay(value) })); op.set('$dateAfter', (value: string) => ({ [Op.gte]: getNextDay(value) }));
// 不早于(含当天) // 不早于(含当天)
op.set('$dateNotBefore', (value: string) => ({ [Op.gte]: stringToDate(value) })); op.set('$dateNotBefore', (value: string) => ({
[Op.gte]: stringToDate(value),
}));
// 不晚于(含当天) // 不晚于(含当天)
op.set('$dateNotAfter', (value: string) => ({ [Op.lt]: getNextDay(value) })); op.set('$dateNotAfter', (value: string) => ({ [Op.lt]: getNextDay(value) }));
// 在期间 // 在期间
op.set('$dateBetween', ([from, to]: string[]) => ({ [Op.and]: [{ [Op.gte]: stringToDate(from) }, { [Op.lt]: getNextDay(to) }] })); op.set('$dateBetween', ([from, to]: string[]) => ({
[Op.and]: [{ [Op.gte]: stringToDate(from) }, { [Op.lt]: getNextDay(to) }],
}));
// 不在期间 // 不在期间
op.set('$dateNotBetween', ([from, to]: string[]) => ({ [Op.or]: [{ [Op.lt]: stringToDate(from) }, { [Op.gte]: getNextDay(to) }] })); op.set('$dateNotBetween', ([from, to]: string[]) => ({
[Op.or]: [{ [Op.lt]: stringToDate(from) }, { [Op.gte]: getNextDay(to) }],
}));
// 多选JSON类型 // 多选JSON类型
@ -96,9 +118,13 @@ op.set('$anyOf', (values: any[], options) => {
return Sequelize.literal(''); return Sequelize.literal('');
} }
const { field, fieldPath } = options; const { field, fieldPath } = options;
const column = fieldPath.split('.').map(name => `"${name}"`).join('.'); const column = fieldPath
const sql = values.map(value => `(${column})::jsonb @> '${JSON.stringify(value)}'`).join(' OR '); .split('.')
console.log(sql); .map((name) => `"${name}"`)
.join('.');
const sql = values
.map((value) => `(${column})::jsonb @> '${JSON.stringify(value)}'`)
.join(' OR ');
return Sequelize.literal(sql); return Sequelize.literal(sql);
}); });
// 包含组中所有值 // 包含组中所有值
@ -113,9 +139,13 @@ op.set('$noneOf', (values: any[], options) => {
return Sequelize.literal(''); return Sequelize.literal('');
} }
const { field, fieldPath } = options; const { field, fieldPath } = options;
const column = fieldPath.split('.').map(name => `"${name}"`).join('.'); const column = fieldPath
const sql = values.map(value => `(${column})::jsonb @> '${JSON.stringify(value)}'`).join(' OR '); .split('.')
console.log(sql); .map((name) => `"${name}"`)
.join('.');
const sql = values
.map((value) => `(${column})::jsonb @> '${JSON.stringify(value)}'`)
.join(' OR ');
return Sequelize.literal(`not (${sql})`); return Sequelize.literal(`not (${sql})`);
}); });
// 与组中值匹配 // 与组中值匹配
@ -125,8 +155,13 @@ op.set('$match', (values: any[], options) => {
return Sequelize.literal(''); return Sequelize.literal('');
} }
const { field, fieldPath } = options; const { field, fieldPath } = options;
const column = fieldPath.split('.').map(name => `"${name}"`).join('.'); const column = fieldPath
const sql = `(${column})::jsonb @> '${JSON.stringify(array)}' AND (${column})::jsonb <@ '${JSON.stringify(array)}'` .split('.')
.map((name) => `"${name}"`)
.join('.');
const sql = `(${column})::jsonb @> '${JSON.stringify(
array,
)}' AND (${column})::jsonb <@ '${JSON.stringify(array)}'`;
return Sequelize.literal(sql); return Sequelize.literal(sql);
}); });
op.set('$notMatch', (values: any[], options) => { op.set('$notMatch', (values: any[], options) => {
@ -135,8 +170,13 @@ op.set('$notMatch', (values: any[], options) => {
return Sequelize.literal(''); return Sequelize.literal('');
} }
const { field, fieldPath } = options; const { field, fieldPath } = options;
const column = fieldPath.split('.').map(name => `"${name}"`).join('.'); const column = fieldPath
const sql = `(${column})::jsonb @> '${JSON.stringify(array)}' AND (${column})::jsonb <@ '${JSON.stringify(array)}'` .split('.')
.map((name) => `"${name}"`)
.join('.');
const sql = `(${column})::jsonb @> '${JSON.stringify(
array,
)}' AND (${column})::jsonb <@ '${JSON.stringify(array)}'`;
return Sequelize.literal(`not (${sql})`); return Sequelize.literal(`not (${sql})`);
// return Sequelize.literal(`(not (${sql})) AND ${column} IS NULL`); // return Sequelize.literal(`(not (${sql})) AND ${column} IS NULL`);
}); });
@ -153,4 +193,4 @@ export default class Operator {
public static register(key: string, fn: Function) { public static register(key: string, fn: Function) {
op.set(key, fn); op.set(key, fn);
} }
}; }

View File

@ -12,16 +12,14 @@ import {
Relation, Relation,
BELONGSTO, BELONGSTO,
BELONGSTOMANY, BELONGSTOMANY,
SORT SORT,
} from './fields'; } from './fields';
import Database from './database'; import Database from './database';
import { Model, ModelCtor } from './model'; import { Model, ModelCtor } from './model';
import _ from 'lodash'; import _ from 'lodash';
import merge from 'deepmerge'; import merge from 'deepmerge';
export interface MergeOptions extends merge.Options { export interface MergeOptions extends merge.Options {}
}
const registeredModels = new Map<string, any>(); const registeredModels = new Map<string, any>();
@ -45,8 +43,8 @@ export function getRegisteredModel(key) {
return key; return key;
} }
export interface TableOptions extends Omit<ModelOptions<Model>, 'name' | 'modelName'> { export interface TableOptions
extends Omit<ModelOptions<Model>, 'name' | 'modelName'> {
/** /**
* ModelOptions name * ModelOptions name
* *
@ -77,7 +75,7 @@ export interface TableOptions extends Omit<ModelOptions<Model>, 'name' | 'modelN
/** /**
* Tabel * Tabel
*/ */
export interface TabelContext { export interface TableContext {
database: Database; database: Database;
} }
@ -96,7 +94,6 @@ export type Reinitialize = boolean | 'modelOnly';
* Model * Model
*/ */
export class Table { export class Table {
protected database: Database; protected database: Database;
protected options: TableOptions; protected options: TableOptions;
@ -134,19 +131,16 @@ export class Table {
public relationTables = new Set<string>(); public relationTables = new Set<string>();
get sortable(): boolean { get sortable(): boolean {
return Array.from(this.fields.values()).some(field => field instanceof SORT); return Array.from(this.fields.values()).some(
(field) => field instanceof SORT,
);
} }
constructor(options: TableOptions, context: TabelContext) { constructor(options: TableOptions, context: TableContext) {
const { database } = context; const { database } = context;
database.runHooks('beforeTableInit', options); database.runHooks('beforeTableInit', options);
database.emit('beforeTableInit', options); database.emit('beforeTableInit', options);
const { const { model, fields = [], indexes = [], sortable } = options;
model,
fields = [],
indexes = [],
sortable,
} = options;
this.options = options; this.options = options;
this.database = database; this.database = database;
// 初始化的时候获取 // 初始化的时候获取
@ -183,7 +177,9 @@ export class Table {
public modelInit(reinitialize: Reinitialize = false) { public modelInit(reinitialize: Reinitialize = false) {
if (reinitialize || !this.Model) { if (reinitialize || !this.Model) {
let DefaultModel = this.defaultModel; let DefaultModel = this.defaultModel;
this.Model = DefaultModel ? (class extends DefaultModel {}) : (class extends Model { }); this.Model = DefaultModel
? class extends DefaultModel {}
: class extends Model {};
this.Model.database = this.database; this.Model.database = this.database;
// 关系的建立是在 model.init 之后在配置中表字段Column和关系Relation都在 fields // 关系的建立是在 model.init 之后在配置中表字段Column和关系Relation都在 fields
// 所以需要单独提炼出 associations 字段,并在 Model.init 之后执行 Model.associate // 所以需要单独提炼出 associations 字段,并在 Model.init 之后执行 Model.associate
@ -194,7 +190,10 @@ export class Table {
if (this.database.isDefined(target)) { if (this.database.isDefined(target)) {
const TargetModel = this.database.getModel(target); const TargetModel = this.database.getModel(target);
// 如果关系表在之后才定义,未设置 targetKey 时targetKey 默认值需要在 target model 初始化之后才能取到 // 如果关系表在之后才定义,未设置 targetKey 时targetKey 默认值需要在 target model 初始化之后才能取到
if (association instanceof BELONGSTO || association instanceof BELONGSTOMANY) { if (
association instanceof BELONGSTO ||
association instanceof BELONGSTOMANY
) {
association.updateOptionsAfterTargetModelBeDefined(); association.updateOptionsAfterTargetModelBeDefined();
} }
this.Model[type](TargetModel, association.getAssociationOptions()); this.Model[type](TargetModel, association.getAssociationOptions());
@ -202,7 +201,7 @@ export class Table {
this.associating.delete(key); this.associating.delete(key);
} }
} }
} };
} }
this.Model.init(this.getModelAttributes(), this.getModelOptions()); this.Model.init(this.getModelAttributes(), this.getModelOptions());
@ -245,12 +244,9 @@ export class Table {
} }
public getModelOptions(): InitOptions { public getModelOptions(): InitOptions {
const { const { name, underscored = true, ...restOptions } = this.options;
name, const hooks =
underscored = true, _.get(this.getModel(), 'options.hooks') || this.options.hooks || {};
...restOptions
} = this.options;
const hooks = _.get(this.getModel(), 'options.hooks') || this.options.hooks || {};
return { return {
underscored, underscored,
modelName: name, modelName: name,
@ -294,9 +290,11 @@ export class Table {
this.fields.clear(); this.fields.clear();
this.associating.clear(); this.associating.clear();
this.associations.clear(); this.associations.clear();
for (const key in fields) {
this.addField(fields[key], false); for (const filed of fields) {
this.addField(filed, false);
} }
this.modelInit(true); this.modelInit(true);
} }
@ -327,7 +325,9 @@ export class Table {
if (!this.options.fields) { if (!this.options.fields) {
this.options.fields = []; this.options.fields = [];
} }
const existIndex = this.options.fields.findIndex(field => field.name === name); const existIndex = this.options.fields.findIndex(
(field) => field.name === name,
);
if (existIndex !== -1) { if (existIndex !== -1) {
this.options.fields.splice(existIndex, 1, options); this.options.fields.splice(existIndex, 1, options);
} else { } else {
@ -344,10 +344,13 @@ export class Table {
if (index === true) { if (index === true) {
this.addIndex(name, false); this.addIndex(name, false);
} else if (typeof index === 'object') { } else if (typeof index === 'object') {
this.addIndex({ this.addIndex(
{
fields: [name], fields: [name],
...index, ...index,
}, false); },
false,
);
} }
this.modelAttributes[name] = field.getAttributeOptions(); this.modelAttributes[name] = field.getAttributeOptions();
} }
@ -363,10 +366,16 @@ export class Table {
* @param indexOptions * @param indexOptions
* @param reinitialize * @param reinitialize
*/ */
public addIndex(indexOptions: string | ModelIndexesOptions, reinitialize: Reinitialize = true) { public addIndex(
const options = typeof indexOptions === 'string' ? { indexOptions: string | ModelIndexesOptions,
reinitialize: Reinitialize = true,
) {
const options =
typeof indexOptions === 'string'
? {
fields: [indexOptions], fields: [indexOptions],
} : indexOptions; }
: indexOptions;
// @ts-ignore // @ts-ignore
const index = Utils.nameIndex(options, this.options.name); const index = Utils.nameIndex(options, this.options.name);
console.log(this.options, { index, options }); console.log(this.options, { index, options });
@ -384,7 +393,10 @@ export class Table {
* @param indexes * @param indexes
* @param reinitialize * @param reinitialize
*/ */
public addIndexes(indexes: Array<string | ModelIndexesOptions>, reinitialize: Reinitialize = true) { public addIndexes(
indexes: Array<string | ModelIndexesOptions>,
reinitialize: Reinitialize = true,
) {
for (const index in indexes) { for (const index in indexes) {
this.addIndex(indexes[index], false); this.addIndex(indexes[index], false);
} }
@ -397,16 +409,12 @@ export class Table {
* @param options * @param options
*/ */
public extend(options: TableOptions, mergeOptions: MergeOptions = {}) { public extend(options: TableOptions, mergeOptions: MergeOptions = {}) {
const { const { fields = [], indexes = [], model, ...restOptions } = options;
fields = [],
indexes = [],
model,
...restOptions
} = options;
if (model) { if (model) {
this.defaultModel = getRegisteredModel(model); this.defaultModel = getRegisteredModel(model);
} }
const { arrayMerge = (target: any[], source: any[]) => source } = mergeOptions; const { arrayMerge = (target: any[], source: any[]) => source } =
mergeOptions;
this.options = merge(this.options, restOptions, { this.options = merge(this.options, restOptions, {
arrayMerge, arrayMerge,
...mergeOptions, ...mergeOptions,

View File

@ -58,6 +58,7 @@ export function toWhere(options: any, context: ToWhereContext = {}) {
ctx, ctx,
model, model,
database, database,
dialect: database.sequelize.getDialect(),
fieldPath: name ? `${name}.${prefix}` : prefix, fieldPath: name ? `${name}.${prefix}` : prefix,
}); });
if (result.constructor.name === 'Literal') { if (result.constructor.name === 'Literal') {

View File

@ -0,0 +1,65 @@
import Application from '../../../server/src/application';
import { getInitSqls, runSql } from '../server';
test('import demo data', async () => {
const app = new Application({
database: {
dialect: 'sqlite',
dialectModule: require('sqlite3'),
storage: 'db.sqlite',
logging: false,
},
});
const plugins = [
'@nocobase/plugin-ui-router',
'@nocobase/plugin-ui-schema',
'@nocobase/plugin-collections',
'@nocobase/plugin-users',
'@nocobase/plugin-action-logs',
'@nocobase/plugin-file-manager',
'@nocobase/plugin-permissions',
'@nocobase/plugin-export',
'@nocobase/plugin-system-settings',
'@nocobase/plugin-china-region',
];
for (const plugin of plugins) {
const pluginPath = `${plugin}/src/server`.replace(
'@nocobase/',
'../../../',
);
app.plugin((await import(pluginPath)).default);
}
await app.load();
await app.db.sync({ force: true });
await app.emitAsync('db.init');
const database = app.db;
const sqls = getInitSqls();
for (const sqlGroup of sqls.part1) {
for (const sql of sqlGroup.split(';')) {
await runSql(sql, database);
}
}
await app.db.getModel('collections').load({
skipExisting: true,
});
await app.db.sync();
for (const sqlGroup of sqls.part2) {
for (const sql of sqlGroup.split(';')) {
try {
await runSql(sql, database);
} catch (e) {
console.error(e);
}
}
}
});

View File

@ -1,4 +1,4 @@
TRUNCATE "ui_schemas" RESTART IDENTITY CASCADE; DELETE FROM "ui_schemas";
INSERT INTO "ui_schemas" ("key", "name", "title", "type", "x-component", "options", "async", "sort", "created_at", "updated_at", "parent_key") VALUES INSERT INTO "ui_schemas" ("key", "name", "title", "type", "x-component", "options", "async", "sort", "created_at", "updated_at", "parent_key") VALUES
('dtu7erjj0q8', NULL, '昵称', 'string', 'Input', '{}', '0', 1, '2021-09-02 15:07:56.984+00', '2021-09-02 15:07:56.984+00', NULL), ('dtu7erjj0q8', NULL, '昵称', 'string', 'Input', '{}', '0', 1, '2021-09-02 15:07:56.984+00', '2021-09-02 15:07:56.984+00', NULL),
('5nqs5glgn5c', NULL, '邮箱', 'string', 'Input', '{"require":true}', '0', 2, '2021-09-02 15:07:57.015+00', '2021-09-02 15:07:57.015+00', NULL), ('5nqs5glgn5c', NULL, '邮箱', 'string', 'Input', '{"require":true}', '0', 2, '2021-09-02 15:07:57.015+00', '2021-09-02 15:07:57.015+00', NULL),

View File

@ -1,4 +1,4 @@
TRUNCATE "collections" RESTART IDENTITY CASCADE; DELETE FROM "collections";
INSERT INTO "collections" ("name", "logging", "title", "privilege", "sortable", "options", "sort", "created_at", "updated_at", "ui_schema_key") VALUES INSERT INTO "collections" ("name", "logging", "title", "privilege", "sortable", "options", "sort", "created_at", "updated_at", "ui_schema_key") VALUES
('users', '1', '用户', 'undelete', '"sort"', '{"createdBy":false,"updatedBy":false}', 2, '2021-09-02 15:07:56.914+00', '2021-09-15 00:59:20.676+00', NULL), ('users', '1', '用户', 'undelete', '"sort"', '{"createdBy":false,"updatedBy":false}', 2, '2021-09-02 15:07:56.914+00', '2021-09-15 00:59:20.676+00', NULL),
('t_fsveob6p269', '1', '顾客', NULL, '"sort"', '{}', 5, '2021-09-12 01:05:52.722+00', '2021-09-18 04:15:23.113+00', NULL), ('t_fsveob6p269', '1', '顾客', NULL, '"sort"', '{}', 5, '2021-09-12 01:05:52.722+00', '2021-09-18 04:15:23.113+00', NULL),

View File

@ -1,4 +1,4 @@
TRUNCATE "fields" RESTART IDENTITY CASCADE; DELETE FROM "fields";
INSERT INTO "fields" ("key", "name", "interface", "data_type", "privilege", "state", "options", "sort", "created_at", "updated_at", "parent_key", "collection_name", "ui_schema_key", "reverse_key") VALUES INSERT INTO "fields" ("key", "name", "interface", "data_type", "privilege", "state", "options", "sort", "created_at", "updated_at", "parent_key", "collection_name", "ui_schema_key", "reverse_key") VALUES
('aun85p76s0v', 'f_l8uuiwcnlw9', 'textarea', 'text', NULL, 1, '{}', 8, '2021-09-12 08:18:46.92+00', '2021-09-12 08:18:46.935+00', NULL, 't_2uhu4szs1kq', 'c2pallk0lge', NULL), ('aun85p76s0v', 'f_l8uuiwcnlw9', 'textarea', 'text', NULL, 1, '{}', 8, '2021-09-12 08:18:46.92+00', '2021-09-12 08:18:46.935+00', NULL, 't_2uhu4szs1kq', 'c2pallk0lge', NULL),
('sj5p2y4ac06', '70enejazumv', 'updatedAt', 'date', 'undelete', 1, '{"field":"updated_at"}', 2, '2021-09-03 08:17:30.543+00', '2021-09-03 08:17:30.555+00', NULL, 't_2uhu4szs1kq', 'lchrxtjm3d5', NULL), ('sj5p2y4ac06', '70enejazumv', 'updatedAt', 'date', 'undelete', 1, '{"field":"updated_at"}', 2, '2021-09-03 08:17:30.543+00', '2021-09-03 08:17:30.555+00', NULL, 't_2uhu4szs1kq', 'lchrxtjm3d5', NULL),

View File

@ -1,4 +1,4 @@
TRUNCATE "routes" RESTART IDENTITY CASCADE; DELETE FROM "routes";
INSERT INTO "routes" ("key", "type", "options", "sort", "created_at", "updated_at", "parent_key", "ui_schema_key") VALUES INSERT INTO "routes" ("key", "type", "options", "sort", "created_at", "updated_at", "parent_key", "ui_schema_key") VALUES
('r_94b8nz6evyh', 'redirect', '{"from":"/","to":"/admin","exact":true}', 1, '2021-09-02 15:07:57.162+00', '2021-09-02 15:07:57.162+00', NULL, NULL), ('r_94b8nz6evyh', 'redirect', '{"from":"/","to":"/admin","exact":true}', 1, '2021-09-02 15:07:57.162+00', '2021-09-02 15:07:57.162+00', NULL, NULL),
('r_w1sa2lfk44v', 'route', '{"path":"/admin/:name(.+)?","component":"AdminLayout","title":"后台"}', 2, '2021-09-02 15:07:57.17+00', '2021-09-02 15:07:57.185+00', NULL, 'qqzzjakwkwl'), ('r_w1sa2lfk44v', 'route', '{"path":"/admin/:name(.+)?","component":"AdminLayout","title":"后台"}', 2, '2021-09-02 15:07:57.17+00', '2021-09-02 15:07:57.185+00', NULL, 'qqzzjakwkwl'),

View File

@ -1,3 +1,4 @@
DELETE FROM "attachments";
INSERT INTO "attachments" ("id", "title", "filename", "extname", "size", "mimetype", "path", "meta", "url", "created_at", "updated_at", "created_by_id", "updated_by_id", "storage_id") VALUES INSERT INTO "attachments" ("id", "title", "filename", "extname", "size", "mimetype", "path", "meta", "url", "created_at", "updated_at", "created_by_id", "updated_by_id", "storage_id") VALUES
(2, 'Nocobase', 'dac1165de10a3373a87ae4e5da9788ab.png', '.png', NULL, 'image/png', '', '{}', 'https://nocobase.oss-cn-beijing.aliyuncs.com/dac1165de10a3373a87ae4e5da9788ab.png', '2021-09-04 01:33:38.878+00', '2021-09-04 01:33:38.878+00', NULL, NULL, 2), (2, 'Nocobase', 'dac1165de10a3373a87ae4e5da9788ab.png', '.png', NULL, 'image/png', '', '{}', 'https://nocobase.oss-cn-beijing.aliyuncs.com/dac1165de10a3373a87ae4e5da9788ab.png', '2021-09-04 01:33:38.878+00', '2021-09-04 01:33:38.878+00', NULL, NULL, 2),
(3, 'grapes-276070_1280', '3451976fea63a882b5fd661aa211693e.jpg', '.jpg', NULL, 'image/jpeg', '', '{}', 'https://nocobase.oss-cn-beijing.aliyuncs.com/3451976fea63a882b5fd661aa211693e.jpg', '2021-09-04 01:34:50.388+00', '2021-09-04 01:34:50.388+00', NULL, 1, 2), (3, 'grapes-276070_1280', '3451976fea63a882b5fd661aa211693e.jpg', '.jpg', NULL, 'image/jpeg', '', '{}', 'https://nocobase.oss-cn-beijing.aliyuncs.com/3451976fea63a882b5fd661aa211693e.jpg', '2021-09-04 01:34:50.388+00', '2021-09-04 01:34:50.388+00', NULL, 1, 2),
@ -27,4 +28,3 @@ INSERT INTO "attachments" ("id", "title", "filename", "extname", "size", "mimety
(26, 'kaffeerad-1543158_1280', '8b94dd8cbecdbbd03e4c2fcfbd1067e7.jpg', '.jpg', NULL, 'image/jpeg', '', '{}', 'https://nocobase.oss-cn-beijing.aliyuncs.com/8b94dd8cbecdbbd03e4c2fcfbd1067e7.jpg', '2021-09-12 07:47:39.63+00', '2021-09-12 07:47:39.63+00', NULL, 1, 2), (26, 'kaffeerad-1543158_1280', '8b94dd8cbecdbbd03e4c2fcfbd1067e7.jpg', '.jpg', NULL, 'image/jpeg', '', '{}', 'https://nocobase.oss-cn-beijing.aliyuncs.com/8b94dd8cbecdbbd03e4c2fcfbd1067e7.jpg', '2021-09-12 07:47:39.63+00', '2021-09-12 07:47:39.63+00', NULL, 1, 2),
(28, 'apple-1609693_1280', '31b7dee511a8d6364fee18411763c188.jpg', '.jpg', NULL, 'image/jpeg', '', '{}', 'https://nocobase.oss-cn-beijing.aliyuncs.com/31b7dee511a8d6364fee18411763c188.jpg', '2021-09-12 07:48:41.367+00', '2021-09-12 07:48:41.367+00', NULL, 1, 2), (28, 'apple-1609693_1280', '31b7dee511a8d6364fee18411763c188.jpg', '.jpg', NULL, 'image/jpeg', '', '{}', 'https://nocobase.oss-cn-beijing.aliyuncs.com/31b7dee511a8d6364fee18411763c188.jpg', '2021-09-12 07:48:41.367+00', '2021-09-12 07:48:41.367+00', NULL, 1, 2),
(29, 'cappuccino-1609932_1280', '8f480c4f1bd3d292ef78fb6847669e51.jpg', '.jpg', NULL, 'image/jpeg', '', '{}', 'https://nocobase.oss-cn-beijing.aliyuncs.com/8f480c4f1bd3d292ef78fb6847669e51.jpg', '2021-09-12 07:48:41.372+00', '2021-09-12 07:48:41.372+00', NULL, 1, 2); (29, 'cappuccino-1609932_1280', '8f480c4f1bd3d292ef78fb6847669e51.jpg', '.jpg', NULL, 'image/jpeg', '', '{}', 'https://nocobase.oss-cn-beijing.aliyuncs.com/8f480c4f1bd3d292ef78fb6847669e51.jpg', '2021-09-12 07:48:41.372+00', '2021-09-12 07:48:41.372+00', NULL, 1, 2);
SELECT setval('attachments_id_seq', (SELECT MAX(id) FROM "attachments"), true);

View File

@ -1,3 +1,4 @@
DELETE FROM "t_2uhu4szs1kq";
INSERT INTO "t_2uhu4szs1kq" ("id", "created_at", "updated_at", "sort", "created_by_id", "updated_by_id", "f_hwenour8ara", "f_hznqtmqljb2", "f_u4i0jrp4uo6", "f_l8uuiwcnlw9") VALUES INSERT INTO "t_2uhu4szs1kq" ("id", "created_at", "updated_at", "sort", "created_by_id", "updated_by_id", "f_hwenour8ara", "f_hznqtmqljb2", "f_u4i0jrp4uo6", "f_l8uuiwcnlw9") VALUES
(1, '2021-09-03 08:19:53.163+00', '2021-09-18 07:50:34.039+00', 70, 1, 1, '这是我们要做的任务这是我们要做的', '2021-09-17 00:00:00+00', 'f1g3r41rdh8', '利本毛所线表体定质花则根物大教斯经前飞能D发科程W目。 阶直少看员片飞飞今西取亲本就条持层品平米今ON孤你七2。 花离定可除展通向业很,斗术真节西严特矿,导养-N群长置便。 深规马细三强低按段事作般习就代它完技O布D枝快。 便报动斗改克离为具影研立特养命规么才设步局方总较共张时什Q肃声的者起开出话。'), (1, '2021-09-03 08:19:53.163+00', '2021-09-18 07:50:34.039+00', 70, 1, 1, '这是我们要做的任务这是我们要做的', '2021-09-17 00:00:00+00', 'f1g3r41rdh8', '利本毛所线表体定质花则根物大教斯经前飞能D发科程W目。 阶直少看员片飞飞今西取亲本就条持层品平米今ON孤你七2。 花离定可除展通向业很,斗术真节西严特矿,导养-N群长置便。 深规马细三强低按段事作般习就代它完技O布D枝快。 便报动斗改克离为具影研立特养命规么才设步局方总较共张时什Q肃声的者起开出话。'),
(2, '2021-09-12 08:01:16.467+00', '2021-09-18 07:50:34.039+00', 71, 1, 1, '批量上传附件', '2021-09-24 00:00:00+00', 'f1g3r41rdh8', '利本毛所线表体定质花则根物大教斯经前飞能D发科程W目。 阶直少看员片飞飞今西取亲本就条持层品平米今ON孤你七2。 花离定可除展通向业很,斗术真节西严特矿,导养-N群长置便。 深规马细三强低按段事作般习就代它完技O布D枝快。 便报动斗改克离为具影研立特养命规么才设步局方总较共张时什Q肃声的者起开出话。'), (2, '2021-09-12 08:01:16.467+00', '2021-09-18 07:50:34.039+00', 71, 1, 1, '批量上传附件', '2021-09-24 00:00:00+00', 'f1g3r41rdh8', '利本毛所线表体定质花则根物大教斯经前飞能D发科程W目。 阶直少看员片飞飞今西取亲本就条持层品平米今ON孤你七2。 花离定可除展通向业很,斗术真节西严特矿,导养-N群长置便。 深规马细三强低按段事作般习就代它完技O布D枝快。 便报动斗改克离为具影研立特养命规么才设步局方总较共张时什Q肃声的者起开出话。'),
@ -5,4 +6,3 @@ INSERT INTO "t_2uhu4szs1kq" ("id", "created_at", "updated_at", "sort", "created_
(4, '2021-09-12 08:02:37.852+00', '2021-09-18 07:50:34.039+00', 72, 1, 1, '包派极都火题折究条', '2021-10-08 00:00:00+00', 'zfowtv6fnel', '利本毛所线表体定质花则根物大教斯经前飞能D发科程W目。 阶直少看员片飞飞今西取亲本就条持层品平米今ON孤你七2。 花离定可除展通向业很,斗术真节西严特矿,导养-N群长置便。 深规马细三强低按段事作般习就代它完技O布D枝快。 便报动斗改克离为具影研立特养命规么才设步局方总较共张时什Q肃声的者起开出话。'), (4, '2021-09-12 08:02:37.852+00', '2021-09-18 07:50:34.039+00', 72, 1, 1, '包派极都火题折究条', '2021-10-08 00:00:00+00', 'zfowtv6fnel', '利本毛所线表体定质花则根物大教斯经前飞能D发科程W目。 阶直少看员片飞飞今西取亲本就条持层品平米今ON孤你七2。 花离定可除展通向业很,斗术真节西严特矿,导养-N群长置便。 深规马细三强低按段事作般习就代它完技O布D枝快。 便报动斗改克离为具影研立特养命规么才设步局方总较共张时什Q肃声的者起开出话。'),
(6, '2021-09-17 01:35:18.379+00', '2021-09-18 07:50:34.039+00', 73, 1, 1, '达到顶峰五十五分', '2021-09-17 00:00:00+00', 'zfowtv6fnel', NULL), (6, '2021-09-17 01:35:18.379+00', '2021-09-18 07:50:34.039+00', 73, 1, 1, '达到顶峰五十五分', '2021-09-17 00:00:00+00', 'zfowtv6fnel', NULL),
(3, '2021-09-12 08:02:20.501+00', '2021-09-18 07:50:34.042+00', 68, 1, 1, '往你周观青整积元路公', '2021-09-24 00:00:00+00', 'lebkfnj3d9i', '利本毛所线表体定质花则根物大教斯经前飞能D发科程W目。 阶直少看员片飞飞今西取亲本就条持层品平米今ON孤你七2。 花离定可除展通向业很,斗术真节西严特矿,导养-N群长置便。 深规马细三强低按段事作般习就代它完技O布D枝快。 便报动斗改克离为具影研立特养命规么才设步局方总较共张时什Q肃声的者起开出话。'); (3, '2021-09-12 08:02:20.501+00', '2021-09-18 07:50:34.042+00', 68, 1, 1, '往你周观青整积元路公', '2021-09-24 00:00:00+00', 'lebkfnj3d9i', '利本毛所线表体定质花则根物大教斯经前飞能D发科程W目。 阶直少看员片飞飞今西取亲本就条持层品平米今ON孤你七2。 花离定可除展通向业很,斗术真节西严特矿,导养-N群长置便。 深规马细三强低按段事作般习就代它完技O布D枝快。 便报动斗改克离为具影研立特养命规么才设步局方总较共张时什Q肃声的者起开出话。');
SELECT setval('t_2uhu4szs1kq_id_seq', (SELECT MAX(id) FROM "t_2uhu4szs1kq"), true);

View File

@ -1,3 +1,4 @@
DELETE FROM "t_fsveob6p269";
INSERT INTO "t_fsveob6p269" ("id", "created_at", "updated_at", "sort", "created_by_id", "updated_by_id", "f_vgw4f62h16e", "f_3det6kr3vn8", "f_x9kmuovlm79", "f_bysgds7j36p", "f_kk4nspj1i28", "f_61znsfh307m") VALUES INSERT INTO "t_fsveob6p269" ("id", "created_at", "updated_at", "sort", "created_by_id", "updated_by_id", "f_vgw4f62h16e", "f_3det6kr3vn8", "f_x9kmuovlm79", "f_bysgds7j36p", "f_kk4nspj1i28", "f_61znsfh307m") VALUES
(2, '2021-09-12 07:41:10.508+00', '2021-09-12 07:41:10.508+00', 2, 1, 1, '庆贝儿', '18910347327', 'khan8z430yx', '2000-02-03 00:00:00+00', '件段两声提局则着除所法军为后出子石了期七小南领能革表相F声化等水坑但F连。 今劳查速布你安约定值斗运通声资区的选心认部样7展期辅些正记。 (2, '2021-09-12 07:41:10.508+00', '2021-09-12 07:41:10.508+00', 2, 1, 1, '庆贝儿', '18910347327', 'khan8z430yx', '2000-02-03 00:00:00+00', '件段两声提局则着除所法军为后出子石了期七小南领能革表相F声化等水坑但F连。 今劳查速布你安约定值斗运通声资区的选心认部样7展期辅些正记。
@ -18,4 +19,3 @@ INSERT INTO "t_fsveob6p269" ("id", "created_at", "updated_at", "sort", "created_
(6, '2021-09-12 07:43:57.617+00', '2021-09-12 08:28:50.544+00', 6, 1, 1, '宓中仕', '13527645198', 'khan8z430yx', '1999-02-26 00:00:00+00', '压界点小名理它车机两得原查去证行村太孟道。求真强记织管装总论形感增委越术市点便定肃容红个而写。代往门张照布活期头劳量人导8新建给。造装话和很片算只类论所全变容时过地传达术族刷车进变了邮盯。 在给情她积音新问整史图火验往受王多式儿花6集听壳是呆。越县管积小与权内有红压往你周观青整积元路公包派极都火题折究条。 (6, '2021-09-12 07:43:57.617+00', '2021-09-12 08:28:50.544+00', 6, 1, 1, '宓中仕', '13527645198', 'khan8z430yx', '1999-02-26 00:00:00+00', '压界点小名理它车机两得原查去证行村太孟道。求真强记织管装总论形感增委越术市点便定肃容红个而写。代往门张照布活期头劳量人导8新建给。造装话和很片算只类论所全变容时过地传达术族刷车进变了邮盯。 在给情她积音新问整史图火验往受王多式儿花6集听壳是呆。越县管积小与权内有红压往你周观青整积元路公包派极都火题折究条。
S点其会 便广M来霸豆板枝E事眼目外4 ', 'z7wq1mkwmmx'); S点其会 便广M来霸豆板枝E事眼目外4 ', 'z7wq1mkwmmx');
SELECT setval('t_fsveob6p269_id_seq', (SELECT MAX(id) FROM "t_fsveob6p269"), true);

View File

@ -1,3 +1,4 @@
DELETE FROM "t_geso7fru7a9";
INSERT INTO "t_geso7fru7a9" ("id", "created_at", "updated_at", "sort", "created_by_id", "updated_by_id", "f_umjewufbyhj", "f_nlgk67tpdql", "f_niymyj0no38") VALUES INSERT INTO "t_geso7fru7a9" ("id", "created_at", "updated_at", "sort", "created_by_id", "updated_by_id", "f_umjewufbyhj", "f_nlgk67tpdql", "f_niymyj0no38") VALUES
(1, '2021-09-12 01:24:52.21+00', '2021-09-12 07:38:07.64+00', 1, 1, 1, '2021-09-10 11:26:28+00', 'x4qnavatfai', '751834123525'), (1, '2021-09-12 01:24:52.21+00', '2021-09-12 07:38:07.64+00', 1, 1, 1, '2021-09-10 11:26:28+00', 'x4qnavatfai', '751834123525'),
(2, '2021-09-12 07:36:07.647+00', '2021-09-12 07:38:15.812+00', 2, 1, 1, '2021-09-24 15:41:03+00', 'i2xjqmnwrsu', '751834123526'), (2, '2021-09-12 07:36:07.647+00', '2021-09-12 07:38:15.812+00', 2, 1, 1, '2021-09-24 15:41:03+00', 'i2xjqmnwrsu', '751834123526'),
@ -15,4 +16,3 @@ INSERT INTO "t_geso7fru7a9" ("id", "created_at", "updated_at", "sort", "created_
(14, '2021-09-14 02:06:10.875+00', '2021-09-14 02:06:10.875+00', 14, 1, 1, '2021-09-07 10:06:06+00', 'x4qnavatfai', '751834123537'), (14, '2021-09-14 02:06:10.875+00', '2021-09-14 02:06:10.875+00', 14, 1, 1, '2021-09-07 10:06:06+00', 'x4qnavatfai', '751834123537'),
(15, '2021-09-14 02:06:29.102+00', '2021-09-14 02:06:29.102+00', 15, 1, 1, '2021-09-25 10:06:18+00', 'x4qnavatfai', '751834123538'), (15, '2021-09-14 02:06:29.102+00', '2021-09-14 02:06:29.102+00', 15, 1, 1, '2021-09-25 10:06:18+00', 'x4qnavatfai', '751834123538'),
(16, '2021-09-14 02:06:45.054+00', '2021-09-14 02:06:45.054+00', 16, 1, 1, '2021-09-09 10:06:41+00', 'i2xjqmnwrsu', '751834123539'); (16, '2021-09-14 02:06:45.054+00', '2021-09-14 02:06:45.054+00', 16, 1, 1, '2021-09-09 10:06:41+00', 'i2xjqmnwrsu', '751834123539');
SELECT setval('t_geso7fru7a9_id_seq', (SELECT MAX(id) FROM "t_geso7fru7a9"), true);

View File

@ -1,3 +1,4 @@
DELETE FROM "t_bphcojtl8bx";
INSERT INTO "t_bphcojtl8bx" ("created_at", "updated_at", "f_cn6a3p0wq2p", "f_4x6u1waa8r6") VALUES INSERT INTO "t_bphcojtl8bx" ("created_at", "updated_at", "f_cn6a3p0wq2p", "f_4x6u1waa8r6") VALUES
('2021-09-12 01:24:52.263+00', '2021-09-12 01:24:52.263+00', 1, 1), ('2021-09-12 01:24:52.263+00', '2021-09-12 01:24:52.263+00', 1, 1),
('2021-09-12 07:36:07.681+00', '2021-09-12 07:36:07.681+00', 1, 2), ('2021-09-12 07:36:07.681+00', '2021-09-12 07:36:07.681+00', 1, 2),

View File

@ -1,3 +1,4 @@
DELETE FROM "t_jh7a28dsfzi";
INSERT INTO "t_jh7a28dsfzi" ("created_at", "updated_at", "f_xg3mysbjfra", "f_gc7ppj0b7n1") VALUES INSERT INTO "t_jh7a28dsfzi" ("created_at", "updated_at", "f_xg3mysbjfra", "f_gc7ppj0b7n1") VALUES
('2021-09-12 01:21:03.65+00', '2021-09-12 01:21:03.65+00', 1, 6), ('2021-09-12 01:21:03.65+00', '2021-09-12 01:21:03.65+00', 1, 6),
('2021-09-12 01:21:03.65+00', '2021-09-12 01:21:03.65+00', 1, 5), ('2021-09-12 01:21:03.65+00', '2021-09-12 01:21:03.65+00', 1, 5),

View File

@ -1,3 +1,4 @@
DELETE FROM "t_p13gbi31uux";
INSERT INTO "t_p13gbi31uux" ("created_at", "updated_at", "f_86s65mbw93e", "f_hwx3hgg5b5t") VALUES INSERT INTO "t_p13gbi31uux" ("created_at", "updated_at", "f_86s65mbw93e", "f_hwx3hgg5b5t") VALUES
('2021-09-12 01:21:03.666+00', '2021-09-12 01:21:03.666+00', 1, '11'), ('2021-09-12 01:21:03.666+00', '2021-09-12 01:21:03.666+00', 1, '11'),
('2021-09-12 01:21:03.666+00', '2021-09-12 01:21:03.666+00', 1, '1101'), ('2021-09-12 01:21:03.666+00', '2021-09-12 01:21:03.666+00', 1, '1101'),

View File

@ -1,3 +1,4 @@
DELETE FROM "roles";
INSERT INTO "roles" ("name", "title", "sort", "created_at", "updated_at", "created_by_id", "updated_by_id") VALUES INSERT INTO "roles" ("name", "title", "sort", "created_at", "updated_at", "created_by_id", "updated_by_id") VALUES
('r_tfs4qtaxjcs', '管理员', 1, '2021-09-14 02:12:19.98+00', '2021-09-14 02:12:19.98+00', 1, 1), ('r_tfs4qtaxjcs', '管理员', 1, '2021-09-14 02:12:19.98+00', '2021-09-14 02:12:19.98+00', 1, 1),
('r_np59b00ex8z', '普通成员', 2, '2021-09-14 02:12:35.799+00', '2021-09-14 02:12:35.799+00', 1, 1); ('r_np59b00ex8z', '普通成员', 2, '2021-09-14 02:12:35.799+00', '2021-09-14 02:12:35.799+00', 1, 1);

View File

@ -1,3 +1,4 @@
DELETE FROM "action_permissions";
INSERT INTO "action_permissions" ("id", "action_name", "created_at", "updated_at", "collection_name", "user_id", "created_by_id", "updated_by_id", "role_name", "scope_id") VALUES INSERT INTO "action_permissions" ("id", "action_name", "created_at", "updated_at", "collection_name", "user_id", "created_by_id", "updated_by_id", "role_name", "scope_id") VALUES
(1, 'create', '2021-09-14 02:19:38.019+00', '2021-09-14 02:19:45.64+00', 't_geso7fru7a9', NULL, 1, 1, NULL, NULL), (1, 'create', '2021-09-14 02:19:38.019+00', '2021-09-14 02:19:45.64+00', 't_geso7fru7a9', NULL, 1, 1, NULL, NULL),
(2, 'get', '2021-09-14 02:19:38.04+00', '2021-09-14 02:19:45.64+00', 't_geso7fru7a9', NULL, 1, 1, NULL, NULL), (2, 'get', '2021-09-14 02:19:38.04+00', '2021-09-14 02:19:45.64+00', 't_geso7fru7a9', NULL, 1, 1, NULL, NULL),
@ -15,4 +16,3 @@ INSERT INTO "action_permissions" ("id", "action_name", "created_at", "updated_at
(10, 'get', '2021-09-14 02:19:53.274+00', '2021-09-14 02:20:00.371+00', 't_fsveob6p269', NULL, 1, 1, NULL, NULL), (10, 'get', '2021-09-14 02:19:53.274+00', '2021-09-14 02:20:00.371+00', 't_fsveob6p269', NULL, 1, 1, NULL, NULL),
(11, 'update', '2021-09-14 02:19:53.284+00', '2021-09-14 02:20:00.371+00', 't_fsveob6p269', NULL, 1, 1, NULL, NULL), (11, 'update', '2021-09-14 02:19:53.284+00', '2021-09-14 02:20:00.371+00', 't_fsveob6p269', NULL, 1, 1, NULL, NULL),
(12, 'destroy', '2021-09-14 02:19:53.294+00', '2021-09-14 02:20:00.371+00', 't_fsveob6p269', NULL, 1, 1, NULL, NULL); (12, 'destroy', '2021-09-14 02:19:53.294+00', '2021-09-14 02:20:00.371+00', 't_fsveob6p269', NULL, 1, 1, NULL, NULL);
SELECT setval('action_permissions_id_seq', (SELECT MAX(id) FROM "action_permissions"), true);

View File

@ -1,3 +1,4 @@
DELETE FROM "field_permissions";
INSERT INTO "field_permissions" ("created_at", "updated_at", "action_permission_id", "field_key") VALUES INSERT INTO "field_permissions" ("created_at", "updated_at", "action_permission_id", "field_key") VALUES
('2021-09-14 02:19:38.034+00', '2021-09-14 02:19:38.034+00', 1, 'nv0iw8wdxmz'), ('2021-09-14 02:19:38.034+00', '2021-09-14 02:19:38.034+00', 1, 'nv0iw8wdxmz'),
('2021-09-14 02:19:38.034+00', '2021-09-14 02:19:38.034+00', 1, 'lu1ibrb0yi2'), ('2021-09-14 02:19:38.034+00', '2021-09-14 02:19:38.034+00', 1, 'lu1ibrb0yi2'),

View File

@ -1,3 +1,4 @@
DELETE FROM "roles_ui_schemas";
INSERT INTO "roles_ui_schemas" ("created_at", "updated_at", "ui_schema_key", "role_name") VALUES INSERT INTO "roles_ui_schemas" ("created_at", "updated_at", "ui_schema_key", "role_name") VALUES
('2021-09-14 02:19:13.669+00', '2021-09-14 02:19:13.669+00', '0b73gccskc2', 'r_tfs4qtaxjcs'), ('2021-09-14 02:19:13.669+00', '2021-09-14 02:19:13.669+00', '0b73gccskc2', 'r_tfs4qtaxjcs'),
('2021-09-14 02:19:13.669+00', '2021-09-14 02:19:13.669+00', 'hall72478p5', 'r_tfs4qtaxjcs'), ('2021-09-14 02:19:13.669+00', '2021-09-14 02:19:13.669+00', 'hall72478p5', 'r_tfs4qtaxjcs'),

View File

@ -0,0 +1,5 @@
SELECT setval('action_permissions_id_seq', (SELECT MAX(id) FROM "action_permissions"), true);
SELECT setval('attachments_id_seq', (SELECT MAX(id) FROM "attachments"), true);
SELECT setval('t_2uhu4szs1kq_id_seq', (SELECT MAX(id) FROM "t_2uhu4szs1kq"), true);
SELECT setval('t_fsveob6p269_id_seq', (SELECT MAX(id) FROM "t_fsveob6p269"), true);
SELECT setval('t_geso7fru7a9_id_seq', (SELECT MAX(id) FROM "t_geso7fru7a9"), true);

View File

@ -5,20 +5,46 @@ import { PluginOptions } from '@nocobase/server';
import { readFileSync } from 'fs'; import { readFileSync } from 'fs';
import glob from 'glob'; import glob from 'glob';
function getInitSqls() { export function getInitSqls(): {
const part1 = []; [key: string]: string[];
const part2 = []; } {
const files1 = glob.sync(path.resolve(__dirname, './db/part1/*.sql')); const dirs = ['part1', 'part2', 'postgres'];
for (const file of files1) { return dirs
const sql = readFileSync(file).toString(); .map((dir) => {
part1.push(sql); return {
dir,
files: glob
.sync(path.resolve(__dirname, `./db/${dir}/*.sql`))
.map((fileName) => readFileSync(fileName).toString()),
};
})
.reduce((carry, dirFiles) => {
carry[dirFiles.dir] = dirFiles.files;
return carry;
}, {});
}
export function runSql(sql, database) {
const trimmed = sql.trim();
if (trimmed.length == 0) {
return;
}
return database.sequelize.query(trimmed, {
raw: true,
logging: false,
});
}
async function runSqlFile(content, database) {
for (const sqlGroup of content) {
for (const sql of sqlGroup.split(';')) {
try {
await runSql(sql, database);
} catch (e) {
console.error({ e, sql });
}
} }
const files2 = glob.sync(path.resolve(__dirname, './db/part2/*.sql'));
for (const file of files2) {
const sql = readFileSync(file).toString();
part2.push(sql);
} }
return { part1, part2 };
} }
export default { export default {
@ -39,33 +65,32 @@ export default {
} }
}); });
const app = this.app; const app = this.app;
this.app.on('db.init', async () => { const cmd = app.findCommand('init');
if (this.options.importDemo !== true) { if (cmd) {
cmd.option('--import-demo');
}
this.app.on('db.init', async (opts, cli) => {
const importDemo = opts.importDemo || this.options.importDemo;
console.log({ importDemo });
if (importDemo !== true) {
return; return;
} }
const transaction = await app.db.sequelize.transaction();
const sqls = getInitSqls(); const sqls = getInitSqls();
try {
for (const sql of sqls.part1) { const database = app.db;
await app.db.sequelize.query(sql, { transaction });
} await runSqlFile(sqls.part1, database);
await transaction.commit();
} catch (error) {
await transaction.rollback();
}
await app.db.getModel('collections').load({ await app.db.getModel('collections').load({
skipExisting: true, skipExisting: true,
}); });
await app.db.sync(); await app.db.sync();
const transaction2 = await app.db.sequelize.transaction();
try { await runSqlFile(sqls.part2, database);
for (const sql of sqls.part2) {
await app.db.sequelize.query(sql, { transaction: transaction2 }); if (app.db.sequelize.getDialect() == 'postgres') {
} await runSqlFile(sqls.postgres, database);
await transaction2.commit();
} catch (error) {
await transaction2.rollback();
} }
}); });
} },
} as PluginOptions; } as PluginOptions;

View File

@ -8,8 +8,8 @@ describe('user fields', () => {
beforeEach(async () => { beforeEach(async () => {
api = mockServer(); api = mockServer();
api.registerPlugin('users', require('../server').default); api.plugin(require('../server').default);
await api.loadPlugins(); await api.load();
db = api.db; db = api.db;
}); });

View File

@ -17,8 +17,8 @@ export default {
const User = database.getModel('users'); const User = database.getModel('users');
await User.create({ await User.create({
nickname: '超级管理员', nickname: '超级管理员',
email: process.env.ADMIN_EMAIL, email: process.env.ADMIN_EMAIL || 'admin@nocobase.com',
password: process.env.ADMIN_PASSWORD, password: process.env.ADMIN_PASSWORD || 'admin',
}); });
}); });

View File

@ -2,8 +2,7 @@ import supertest from 'supertest';
import { Application } from '../application'; import { Application } from '../application';
import { Plugin } from '../plugin'; import { Plugin } from '../plugin';
class MyPlugin extends Plugin { class MyPlugin extends Plugin {}
}
describe('application', () => { describe('application', () => {
let app: Application; let app: Application;
@ -12,21 +11,15 @@ describe('application', () => {
beforeEach(() => { beforeEach(() => {
app = new Application({ app = new Application({
database: { database: {
username: process.env.DB_USER, dialect: 'sqlite',
password: process.env.DB_PASSWORD, dialectModule: require('sqlite3'),
database: process.env.DB_DATABASE, storage: ':memory:',
host: process.env.DB_HOST,
port: process.env.DB_PORT as any,
dialect: process.env.DB_DIALECT as any,
dialectOptions: {
charset: 'utf8mb4',
collate: 'utf8mb4_unicode_ci',
},
}, },
resourcer: { resourcer: {
prefix: '/api', prefix: '/api',
}, },
dataWrapping: false, dataWrapping: false,
registerActions: false,
}); });
app.resourcer.registerActionHandlers({ app.resourcer.registerActionHandlers({
list: async (ctx, next) => { list: async (ctx, next) => {
@ -84,7 +77,7 @@ describe('application', () => {
{ {
type: 'hasMany', type: 'hasMany',
name: 'bars', name: 'bars',
} },
], ],
}); });
const response = await agent.get('/api/foos/1/bars'); const response = await agent.get('/api/foos/1/bars');
@ -92,7 +85,7 @@ describe('application', () => {
}); });
it('db.middleware', async () => { it('db.middleware', async () => {
const index = app.middleware.findIndex(m => m.name === 'table2resource'); const index = app.middleware.findIndex((m) => m.name === 'table2resource');
app.middleware.splice(index, 0, async (ctx, next) => { app.middleware.splice(index, 0, async (ctx, next) => {
app.db.table({ app.db.table({
name: 'tests', name: 'tests',
@ -104,7 +97,7 @@ describe('application', () => {
}); });
it('db.middleware', async () => { it('db.middleware', async () => {
const index = app.middleware.findIndex(m => m.name === 'table2resource'); const index = app.middleware.findIndex((m) => m.name === 'table2resource');
app.middleware.splice(index, 0, async (ctx, next) => { app.middleware.splice(index, 0, async (ctx, next) => {
app.db.table({ app.db.table({
name: 'bars', name: 'bars',
@ -115,7 +108,7 @@ describe('application', () => {
{ {
type: 'hasMany', type: 'hasMany',
name: 'bars', name: 'bars',
} },
], ],
}); });
await next(); await next();

View File

@ -1,12 +1,15 @@
import Koa from 'koa'; import Koa from 'koa';
import cors from '@koa/cors';
import bodyParser from 'koa-bodyparser';
import { Command, CommandOptions } from 'commander'; import { Command, CommandOptions } from 'commander';
import Database, { DatabaseOptions, TableOptions } from '@nocobase/database'; import Database, { DatabaseOptions, TableOptions } from '@nocobase/database';
import Resourcer, { ResourceOptions } from '@nocobase/resourcer'; import Resourcer, { ResourceOptions } from '@nocobase/resourcer';
import { dataWrapping, table2resource } from './middlewares';
import { PluginType, Plugin, PluginOptions } from './plugin'; import { PluginType, Plugin, PluginOptions } from './plugin';
import { registerActions } from '@nocobase/actions'; import { registerActions } from '@nocobase/actions';
import {
createCli,
createDatabase,
createResourcer,
registerMiddlewares,
} from './helper';
export interface ResourcerOptions { export interface ResourcerOptions {
prefix?: string; prefix?: string;
@ -18,6 +21,7 @@ export interface ApplicationOptions {
bodyParser?: any; bodyParser?: any;
cors?: any; cors?: any;
dataWrapping?: boolean; dataWrapping?: boolean;
registerActions?: boolean;
} }
interface DefaultState { interface DefaultState {
@ -46,7 +50,7 @@ interface ActionsOptions {
export class Application< export class Application<
StateT = DefaultState, StateT = DefaultState,
ContextT = DefaultContext, ContextT = DefaultContext
> extends Koa { > extends Koa {
public readonly db: Database; public readonly db: Database;
@ -59,91 +63,14 @@ export class Application<
constructor(options: ApplicationOptions) { constructor(options: ApplicationOptions) {
super(); super();
if (options.database instanceof Database) { this.db = createDatabase(options);
this.db = options.database; this.resourcer = createResourcer(options);
} else { this.cli = createCli(this, options);
this.db = new Database(options.database);
}
this.resourcer = new Resourcer({ ...options.resourcer });
this.cli = new Command();
if (options.bodyParser !== false) {
this.use(
bodyParser({
...options.bodyParser,
}),
);
}
this.use(
cors({
exposeHeaders: ['content-disposition'],
...options.cors,
}),
);
this.use<DefaultState, DefaultContext>(async (ctx, next) => {
ctx.db = this.db;
ctx.resourcer = this.resourcer;
await next();
});
if (options.dataWrapping !== false) {
this.use(dataWrapping());
}
this.use(table2resource());
this.use(this.resourcer.restApiMiddleware());
registerMiddlewares(this, options);
if (options.registerActions !== false) {
registerActions(this); registerActions(this);
this.cli
.command('db:sync')
.option('-f, --force')
.action(async (...args) => {
console.log('db sync...');
const cli = args.pop();
const force = cli.opts()?.force;
await this.db.sync(
force
? {
force: true,
alter: {
drop: true,
},
} }
: {},
);
await this.destroy();
});
this.cli
.command('init')
// .option('-f, --force')
.action(async (...args) => {
const cli = args.pop();
await this.db.sync({
force: true,
alter: {
drop: true,
},
});
await this.emitAsync('db.init');
await this.destroy();
});
this.cli
.command('start')
.option('-p, --port [port]')
.action(async (...args) => {
const cli = args.pop();
console.log(args);
const opts = cli.opts();
await this.emitAsync('beforeStart');
this.listen(opts.port || 3000);
console.log(`http://localhost:${opts.port || 3000}/`);
});
} }
use<NewStateT = {}, NewContextT = {}>( use<NewStateT = {}, NewContextT = {}>(
@ -170,6 +97,10 @@ export class Application<
return this.cli.command(nameAndArgs, opts); return this.cli.command(nameAndArgs, opts);
} }
findCommand(name: string): Command {
return (this.cli as any)._findCommand(name);
}
plugin(options?: PluginType | PluginOptions, ext?: PluginOptions): Plugin { plugin(options?: PluginType | PluginOptions, ext?: PluginOptions): Plugin {
if (typeof options === 'string') { if (typeof options === 'string') {
return this.plugin(require(options).default, ext); return this.plugin(require(options).default, ext);

View File

@ -0,0 +1,100 @@
import { DefaultContext, DefaultState } from 'koa';
import bodyParser from 'koa-bodyparser';
import cors from '@koa/cors';
import Database from '@nocobase/database';
import Resourcer from '@nocobase/resourcer';
import { Command } from 'commander';
import Application, { ApplicationOptions } from './application';
import { dataWrapping } from './middlewares/data-wrapping';
import { table2resource } from './middlewares/table2resource';
export function createDatabase(options: ApplicationOptions) {
if (options.database instanceof Database) {
return options.database;
} else {
return new Database(options.database);
}
}
export function createResourcer(options: ApplicationOptions) {
return new Resourcer({ ...options.resourcer });
}
export function createCli(app, options: ApplicationOptions) {
const cli = new Command();
cli
.command('db:sync')
.option('-f, --force')
.action(async (...args) => {
console.log('db sync...');
const cli = args.pop();
const force = cli.opts()?.force;
await app.db.sync(
force
? {
force: true,
alter: {
drop: true,
},
}
: {},
);
await app.destroy();
});
cli
.command('init')
.option('-f, --force')
.action(async (...args) => {
await app.db.sync({
force: true,
});
await app.emitAsync('db.init', ...args);
await app.destroy();
});
cli
.command('start')
.option('-p, --port [port]')
.action(async (...args) => {
const cli = args.pop();
const opts = cli.opts();
await app.emitAsync('beforeStart');
app.listen(opts.port || 3000);
console.log(`http://localhost:${opts.port || 3000}/`);
});
return cli;
}
export function registerMiddlewares(
app: Application,
options: ApplicationOptions,
) {
if (options.bodyParser !== false) {
app.use(
bodyParser({
...options.bodyParser,
}),
);
}
app.use(
cors({
exposeHeaders: ['content-disposition'],
...options.cors,
}),
);
app.use<DefaultState, DefaultContext>(async (ctx, next) => {
ctx.db = app.db;
ctx.resourcer = app.resourcer;
await next();
});
if (options.dataWrapping !== false) {
app.use(dataWrapping());
}
app.use(table2resource());
app.use(app.resourcer.restApiMiddleware());
}

305
yarn.lock
View File

@ -4080,10 +4080,17 @@
"@types/prop-types" "*" "@types/prop-types" "*"
"@types/react" "*" "@types/react" "*"
"@types/react-dom@^16.9.8", "@types/react-dom@^17.0.0", "@types/react-dom@^17.0.3": "@types/react-dom@^16.9.8":
version "16.9.14"
resolved "https://registry.nlark.com/@types/react-dom/download/@types/react-dom-16.9.14.tgz?cache=0&sync_timestamp=1629708935856&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Freact-dom%2Fdownload%2F%40types%2Freact-dom-16.9.14.tgz#674b8f116645fe5266b40b525777fc6bb8eb3bcd"
integrity sha1-Z0uPEWZF/lJmtAtSV3f8a7jrO80=
dependencies:
"@types/react" "^16"
"@types/react-dom@^17.0.3":
version "17.0.9" version "17.0.9"
resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz#441a981da9d7be117042e1a6fd3dac4b30f55add" resolved "https://registry.nlark.com/@types/react-dom/download/@types/react-dom-17.0.9.tgz#441a981da9d7be117042e1a6fd3dac4b30f55add"
integrity sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg== integrity sha1-RBqYHanXvhFwQuGm/T2sSzD1Wt0=
dependencies: dependencies:
"@types/react" "*" "@types/react" "*"
@ -4156,7 +4163,7 @@
"@types/history" "*" "@types/history" "*"
"@types/react" "*" "@types/react" "*"
"@types/react@*", "@types/react@>=16.9.11", "@types/react@^16.9.43", "@types/react@^17.0.0": "@types/react@*", "@types/react@>=16.9.11", "@types/react@^17.0.0":
version "17.0.18" version "17.0.18"
resolved "https://registry.npmjs.org/@types/react/-/react-17.0.18.tgz#4109cbbd901be9582e5e39e3d77acd7b66bb7fbe" resolved "https://registry.npmjs.org/@types/react/-/react-17.0.18.tgz#4109cbbd901be9582e5e39e3d77acd7b66bb7fbe"
integrity sha512-YTLgu7oS5zvSqq49X5Iue5oAbVGhgPc5Au29SJC4VeE17V6gASoOxVkUDy9pXFMRFxCWCD9fLeweNFizo3UzOg== integrity sha512-YTLgu7oS5zvSqq49X5Iue5oAbVGhgPc5Au29SJC4VeE17V6gASoOxVkUDy9pXFMRFxCWCD9fLeweNFizo3UzOg==
@ -4165,6 +4172,15 @@
"@types/scheduler" "*" "@types/scheduler" "*"
csstype "^3.0.2" csstype "^3.0.2"
"@types/react@^16", "@types/react@^16.9.43":
version "16.14.17"
resolved "https://registry.npmmirror.com/@types/react/download/@types/react-16.14.17.tgz?cache=0&sync_timestamp=1634220794290&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40types%2Freact%2Fdownload%2F%40types%2Freact-16.14.17.tgz#c57fcfb05efa6423f5b65fcd4a75f63f05b162bf"
integrity sha1-xX/PsF76ZCP1tl/NSnX2PwWxYr8=
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/resolve@1.17.1": "@types/resolve@1.17.1":
version "1.17.1" version "1.17.1"
resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
@ -5869,7 +5885,7 @@ balanced-match@^1.0.0:
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
base64-js@^1.0.2: base64-js@^1.0.2, base64-js@^1.3.1:
version "1.5.1" version "1.5.1"
resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
@ -5937,11 +5953,27 @@ bindings@^1.5.0:
dependencies: dependencies:
file-uri-to-path "1.0.0" file-uri-to-path "1.0.0"
bl@^4.1.0:
version "4.1.0"
resolved "https://registry.nlark.com/bl/download/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
integrity sha1-RRU1JkGCvsL7vIOmKrmM8R2fezo=
dependencies:
buffer "^5.5.0"
inherits "^2.0.4"
readable-stream "^3.4.0"
blessed@0.1.81: blessed@0.1.81:
version "0.1.81" version "0.1.81"
resolved "https://registry.npmjs.org/blessed/-/blessed-0.1.81.tgz#f962d687ec2c369570ae71af843256e6d0ca1129" resolved "https://registry.npmjs.org/blessed/-/blessed-0.1.81.tgz#f962d687ec2c369570ae71af843256e6d0ca1129"
integrity sha1-+WLWh+wsNpVwrnGvhDJW5tDKESk= integrity sha1-+WLWh+wsNpVwrnGvhDJW5tDKESk=
block-stream@*:
version "0.0.9"
resolved "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=
dependencies:
inherits "~2.0.0"
bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5: bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5:
version "3.7.2" version "3.7.2"
resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
@ -6168,6 +6200,14 @@ buffer@^4.3.0:
ieee754 "^1.1.4" ieee754 "^1.1.4"
isarray "^1.0.0" isarray "^1.0.0"
buffer@^5.5.0:
version "5.7.1"
resolved "https://registry.npm.taobao.org/buffer/download/buffer-5.7.1.tgz?cache=0&sync_timestamp=1606098073225&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbuffer%2Fdownload%2Fbuffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
integrity sha1-umLnwTEzBTWCGXFghRqPZI6Z7tA=
dependencies:
base64-js "^1.3.1"
ieee754 "^1.1.13"
builtin-modules@^3.0.0, builtin-modules@^3.1.0: builtin-modules@^3.0.0, builtin-modules@^3.1.0:
version "3.2.0" version "3.2.0"
resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887" resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887"
@ -6617,6 +6657,18 @@ cli-cursor@^2.1.0:
dependencies: dependencies:
restore-cursor "^2.0.0" restore-cursor "^2.0.0"
cli-cursor@^3.1.0:
version "3.1.0"
resolved "https://registry.nlark.com/cli-cursor/download/cli-cursor-3.1.0.tgz?cache=0&sync_timestamp=1629747481175&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcli-cursor%2Fdownload%2Fcli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
integrity sha1-JkMFp65JDR0Dvwybp8kl0XU68wc=
dependencies:
restore-cursor "^3.1.0"
cli-spinners@^2.5.0:
version "2.6.1"
resolved "https://registry.npmmirror.com/cli-spinners/download/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d"
integrity sha1-rclU6+KBw3pjGb+kAebdJIj/tw0=
cli-tableau@^2.0.0: cli-tableau@^2.0.0:
version "2.0.1" version "2.0.1"
resolved "https://registry.npmjs.org/cli-tableau/-/cli-tableau-2.0.1.tgz#baa78d83e08a2d7ab79b7dad9406f0254977053f" resolved "https://registry.npmjs.org/cli-tableau/-/cli-tableau-2.0.1.tgz#baa78d83e08a2d7ab79b7dad9406f0254977053f"
@ -6864,6 +6916,11 @@ commander@^2.19.0, commander@^2.20.0:
resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
commander@^8.2.0:
version "8.2.0"
resolved "https://registry.nlark.com/commander/download/commander-8.2.0.tgz#37fe2bde301d87d47a53adeff8b5915db1381ca8"
integrity sha1-N/4r3jAdh9R6U63v+LWRXbE4HKg=
commander@~2.14.1: commander@~2.14.1:
version "2.14.1" version "2.14.1"
resolved "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" resolved "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa"
@ -7339,7 +7396,7 @@ cross-spawn@^6.0.0:
shebang-command "^1.2.0" shebang-command "^1.2.0"
which "^1.2.9" which "^1.2.9"
cross-spawn@^7.0.0, cross-spawn@^7.0.2: cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3" version "7.0.3"
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
@ -7994,7 +8051,7 @@ detect-indent@^5.0.0:
resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d"
integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50= integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50=
detect-libc@^1.0.3: detect-libc@^1.0.2, detect-libc@^1.0.3:
version "1.0.3" version "1.0.3"
resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
@ -8990,6 +9047,21 @@ execa@^4.0.0:
signal-exit "^3.0.2" signal-exit "^3.0.2"
strip-final-newline "^2.0.0" strip-final-newline "^2.0.0"
execa@^5.1.1:
version "5.1.1"
resolved "https://registry.nlark.com/execa/download/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
integrity sha1-+ArZy/Qpj3vR1MlVXCHpN0HEEd0=
dependencies:
cross-spawn "^7.0.3"
get-stream "^6.0.0"
human-signals "^2.1.0"
is-stream "^2.0.0"
merge-stream "^2.0.0"
npm-run-path "^4.0.1"
onetime "^5.1.2"
signal-exit "^3.0.3"
strip-final-newline "^2.0.0"
exenv@^1.2.0: exenv@^1.2.0:
version "1.2.2" version "1.2.2"
resolved "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" resolved "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
@ -9537,6 +9609,16 @@ fsevents@~2.1.2:
resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
fstream@^1.0.0, fstream@^1.0.12:
version "1.0.12"
resolved "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==
dependencies:
graceful-fs "^4.1.2"
inherits "~2.0.0"
mkdirp ">=0.5 0"
rimraf "2"
ftp@^0.3.10: ftp@^0.3.10:
version "0.3.10" version "0.3.10"
resolved "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d" resolved "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d"
@ -9677,6 +9759,11 @@ get-stream@^5.0.0, get-stream@^5.1.0:
dependencies: dependencies:
pump "^3.0.0" pump "^3.0.0"
get-stream@^6.0.0:
version "6.0.1"
resolved "https://registry.nlark.com/get-stream/download/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
integrity sha1-omLY7vZ6ztV8KFKtYWdSakPL97c=
get-uri@3: get-uri@3:
version "3.0.2" version "3.0.2"
resolved "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz#f0ef1356faabc70e1f9404fa3b66b2ba9bfc725c" resolved "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz#f0ef1356faabc70e1f9404fa3b66b2ba9bfc725c"
@ -9808,6 +9895,18 @@ glob-to-regexp@^0.3.0:
resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
glob@^7.0.3:
version "7.2.0"
resolved "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
version "7.1.7" version "7.1.7"
resolved "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" resolved "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
@ -10483,6 +10582,11 @@ human-signals@^1.1.1:
resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
human-signals@^2.1.0:
version "2.1.0"
resolved "https://registry.nlark.com/human-signals/download/human-signals-2.1.0.tgz?cache=0&sync_timestamp=1624364695595&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhuman-signals%2Fdownload%2Fhuman-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
integrity sha1-3JH8ukLk0G5Kuu0zs+ejwC9RTqA=
humanize-ms@^1.2.0, humanize-ms@^1.2.1: humanize-ms@^1.2.0, humanize-ms@^1.2.1:
version "1.2.1" version "1.2.1"
resolved "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" resolved "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed"
@ -10516,7 +10620,7 @@ identity-obj-proxy@3.0.0:
dependencies: dependencies:
harmony-reflect "^1.4.6" harmony-reflect "^1.4.6"
ieee754@^1.1.4: ieee754@^1.1.13, ieee754@^1.1.4:
version "1.2.1" version "1.2.1"
resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
@ -10683,7 +10787,7 @@ inflight@^1.0.4:
once "^1.3.0" once "^1.3.0"
wrappy "1" wrappy "1"
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
version "2.0.4" version "2.0.4"
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@ -11062,6 +11166,11 @@ is-installed-globally@^0.3.1:
global-dirs "^2.0.1" global-dirs "^2.0.1"
is-path-inside "^3.0.1" is-path-inside "^3.0.1"
is-interactive@^1.0.0:
version "1.0.0"
resolved "https://registry.nlark.com/is-interactive/download/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
integrity sha1-zqbmrlyHCnsKAAQHC3tYfgJSkS4=
is-module@^1.0.0: is-module@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" resolved "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
@ -11269,6 +11378,11 @@ is-unc-path@^1.0.0:
dependencies: dependencies:
unc-path-regex "^0.1.2" unc-path-regex "^0.1.2"
is-unicode-supported@^0.1.0:
version "0.1.0"
resolved "https://registry.nlark.com/is-unicode-supported/download/is-unicode-supported-0.1.0.tgz?cache=0&sync_timestamp=1625294161966&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fis-unicode-supported%2Fdownload%2Fis-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
integrity sha1-PybHaoCVk7Ur+i7LVxDtJ3m1Iqc=
is-url@1.2.4: is-url@1.2.4:
version "1.2.4" version "1.2.4"
resolved "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" resolved "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52"
@ -12949,6 +13063,14 @@ log-driver@^1.2.7:
resolved "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8" resolved "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8"
integrity sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg== integrity sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==
log-symbols@^4.1.0:
version "4.1.0"
resolved "https://registry.npm.taobao.org/log-symbols/download/log-symbols-4.1.0.tgz?cache=0&sync_timestamp=1618723146520&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flog-symbols%2Fdownload%2Flog-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
integrity sha1-P727lbRoOsn8eFER55LlWNSr1QM=
dependencies:
chalk "^4.1.0"
is-unicode-supported "^0.1.0"
long-timeout@0.1.1: long-timeout@0.1.1:
version "0.1.1" version "0.1.1"
resolved "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz#9721d788b47e0bcb5a24c2e2bee1a0da55dab514" resolved "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz#9721d788b47e0bcb5a24c2e2bee1a0da55dab514"
@ -13686,7 +13808,7 @@ mkdirp@*, mkdirp@1.0.4, mkdirp@1.x, mkdirp@^1.0.3, mkdirp@^1.0.4:
resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.4, mkdirp@^0.5.5, mkdirp@~0.5.1: "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.4, mkdirp@^0.5.5, mkdirp@~0.5.1:
version "0.5.5" version "0.5.5"
resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
@ -13885,6 +14007,15 @@ needle@2.4.0:
iconv-lite "^0.4.4" iconv-lite "^0.4.4"
sax "^1.2.4" sax "^1.2.4"
needle@^2.2.1:
version "2.9.1"
resolved "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz#22d1dffbe3490c2b83e301f7709b6736cd8f2684"
integrity sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==
dependencies:
debug "^3.2.6"
iconv-lite "^0.4.4"
sax "^1.2.4"
negotiator@0.6.2: negotiator@0.6.2:
version "0.6.2" version "0.6.2"
resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
@ -13923,7 +14054,7 @@ no-case@^3.0.4:
lower-case "^2.0.2" lower-case "^2.0.2"
tslib "^2.0.3" tslib "^2.0.3"
node-addon-api@^3.1.0: node-addon-api@^3.0.0, node-addon-api@^3.1.0:
version "3.2.1" version "3.2.1"
resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161"
integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==
@ -13955,6 +14086,24 @@ node-fetch@^2.5.0, node-fetch@^2.6.1:
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
node-gyp@3.x:
version "3.8.0"
resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c"
integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==
dependencies:
fstream "^1.0.0"
glob "^7.0.3"
graceful-fs "^4.1.2"
mkdirp "^0.5.0"
nopt "2 || 3"
npmlog "0 || 1 || 2 || 3 || 4"
osenv "0"
request "^2.87.0"
rimraf "2"
semver "~5.3.0"
tar "^2.0.0"
which "1"
node-gyp@^5.0.2: node-gyp@^5.0.2:
version "5.1.1" version "5.1.1"
resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.1.tgz#eb915f7b631c937d282e33aed44cb7a025f62a3e" resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.1.tgz#eb915f7b631c937d282e33aed44cb7a025f62a3e"
@ -14034,6 +14183,22 @@ node-notifier@^8.0.0:
uuid "^8.3.0" uuid "^8.3.0"
which "^2.0.2" which "^2.0.2"
node-pre-gyp@^0.11.0:
version "0.11.0"
resolved "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054"
integrity sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==
dependencies:
detect-libc "^1.0.2"
mkdirp "^0.5.1"
needle "^2.2.1"
nopt "^4.0.1"
npm-packlist "^1.1.6"
npmlog "^4.0.2"
rc "^1.2.7"
rimraf "^2.6.1"
semver "^5.3.0"
tar "^4"
node-releases@^1.1.73: node-releases@^1.1.73:
version "1.1.74" version "1.1.74"
resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.74.tgz#e5866488080ebaa70a93b91144ccde06f3c3463e" resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.74.tgz#e5866488080ebaa70a93b91144ccde06f3c3463e"
@ -14086,6 +14251,13 @@ nodemon@^2.0.12:
undefsafe "^2.0.3" undefsafe "^2.0.3"
update-notifier "^4.1.0" update-notifier "^4.1.0"
"nopt@2 || 3":
version "3.0.6"
resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k=
dependencies:
abbrev "1"
nopt@^4.0.1: nopt@^4.0.1:
version "4.0.3" version "4.0.3"
resolved "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" resolved "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48"
@ -14218,7 +14390,7 @@ npm-normalize-package-bin@^1.0.0, npm-normalize-package-bin@^1.0.1:
semver "^5.6.0" semver "^5.6.0"
validate-npm-package-name "^3.0.0" validate-npm-package-name "^3.0.0"
npm-packlist@^1.4.4: npm-packlist@^1.1.6, npm-packlist@^1.4.4:
version "1.4.8" version "1.4.8"
resolved "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" resolved "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e"
integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==
@ -14243,14 +14415,14 @@ npm-run-path@^2.0.0:
dependencies: dependencies:
path-key "^2.0.0" path-key "^2.0.0"
npm-run-path@^4.0.0: npm-run-path@^4.0.0, npm-run-path@^4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
dependencies: dependencies:
path-key "^3.0.0" path-key "^3.0.0"
npmlog@^4.1.2: "npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.2, npmlog@^4.1.2:
version "4.1.2" version "4.1.2"
resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
@ -14426,7 +14598,7 @@ onetime@^2.0.0:
dependencies: dependencies:
mimic-fn "^1.0.0" mimic-fn "^1.0.0"
onetime@^5.1.0: onetime@^5.1.0, onetime@^5.1.2:
version "5.1.2" version "5.1.2"
resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
@ -14462,6 +14634,21 @@ optionator@^0.9.1:
type-check "^0.4.0" type-check "^0.4.0"
word-wrap "^1.2.3" word-wrap "^1.2.3"
ora@^5.4.1:
version "5.4.1"
resolved "https://registry.nlark.com/ora/download/ora-5.4.1.tgz?cache=0&sync_timestamp=1631556513877&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fora%2Fdownload%2Fora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18"
integrity sha1-GyZ4Qmr0rEpQkAjl5KyemVnbnhg=
dependencies:
bl "^4.1.0"
chalk "^4.1.0"
cli-cursor "^3.1.0"
cli-spinners "^2.5.0"
is-interactive "^1.0.0"
is-unicode-supported "^0.1.0"
log-symbols "^4.1.0"
strip-ansi "^6.0.0"
wcwidth "^1.0.1"
ordered-read-streams@^1.0.0: ordered-read-streams@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz#77c0cb37c41525d64166d990ffad7ec6a0e1363e" resolved "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz#77c0cb37c41525d64166d990ffad7ec6a0e1363e"
@ -14500,7 +14687,7 @@ os-tmpdir@^1.0.0, os-tmpdir@~1.0.2:
resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
osenv@^0.1.4, osenv@^0.1.5: osenv@0, osenv@^0.1.4, osenv@^0.1.5:
version "0.1.5" version "0.1.5"
resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
@ -16793,7 +16980,7 @@ rc-virtual-list@^3.0.1, rc-virtual-list@^3.2.0:
rc-resize-observer "^1.0.0" rc-resize-observer "^1.0.0"
rc-util "^5.0.7" rc-util "^5.0.7"
rc@^1.2.8: rc@^1.2.7, rc@^1.2.8:
version "1.2.8" version "1.2.8"
resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
@ -17217,7 +17404,7 @@ readable-stream@1.1.x:
isarray "0.0.1" isarray "0.0.1"
string_decoder "~0.10.x" string_decoder "~0.10.x"
"readable-stream@2 || 3", readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.6.0: "readable-stream@2 || 3", readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.4.0, readable-stream@^3.6.0:
version "3.6.0" version "3.6.0"
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
@ -17709,6 +17896,14 @@ restore-cursor@^2.0.0:
onetime "^2.0.0" onetime "^2.0.0"
signal-exit "^3.0.2" signal-exit "^3.0.2"
restore-cursor@^3.1.0:
version "3.1.0"
resolved "https://registry.nlark.com/restore-cursor/download/restore-cursor-3.1.0.tgz?cache=0&sync_timestamp=1629746923086&other_urls=https%3A%2F%2Fregistry.nlark.com%2Frestore-cursor%2Fdownload%2Frestore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
integrity sha1-OfZ8VLOnpYzqUjbZXPADQjljH34=
dependencies:
onetime "^5.1.0"
signal-exit "^3.0.2"
ret@~0.1.10: ret@~0.1.10:
version "0.1.15" version "0.1.15"
resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
@ -17748,6 +17943,13 @@ right-align@^0.1.1:
dependencies: dependencies:
align-text "^0.1.1" align-text "^0.1.1"
rimraf@2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3:
version "2.7.1"
resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
dependencies:
glob "^7.1.3"
rimraf@2.6.3: rimraf@2.6.3:
version "2.6.3" version "2.6.3"
resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
@ -17755,13 +17957,6 @@ rimraf@2.6.3:
dependencies: dependencies:
glob "^7.1.3" glob "^7.1.3"
rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3:
version "2.7.1"
resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
dependencies:
glob "^7.1.3"
rimraf@^3.0.0, rimraf@^3.0.2: rimraf@^3.0.0, rimraf@^3.0.2:
version "3.0.2" version "3.0.2"
resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
@ -18239,6 +18434,11 @@ semver@7.x, semver@^7.2, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.
dependencies: dependencies:
lru-cache "^6.0.0" lru-cache "^6.0.0"
semver@~5.3.0:
version "5.3.0"
resolved "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8=
semver@~7.2.0: semver@~7.2.0:
version "7.2.3" version "7.2.3"
resolved "https://registry.npmjs.org/semver/-/semver-7.2.3.tgz#3641217233c6382173c76bf2c7ecd1e1c16b0d8a" resolved "https://registry.npmjs.org/semver/-/semver-7.2.3.tgz#3641217233c6382173c76bf2c7ecd1e1c16b0d8a"
@ -18254,6 +18454,25 @@ sequelize-pool@^6.0.0:
resolved "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz#caaa0c1e324d3c2c3a399fed2c7998970925d668" resolved "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz#caaa0c1e324d3c2c3a399fed2c7998970925d668"
integrity sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg== integrity sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg==
sequelize@6.7.0:
version "6.7.0"
resolved "https://registry.npmmirror.com/sequelize/download/sequelize-6.7.0.tgz#6af3149ad9b39c4bfc8b563f25e1598e2a0cf881"
integrity sha1-avMUmtmznEv8i1Y/JeFZjioM+IE=
dependencies:
debug "^4.1.1"
dottie "^2.0.0"
inflection "1.13.1"
lodash "^4.17.20"
moment "^2.26.0"
moment-timezone "^0.5.31"
retry-as-promised "^3.2.0"
semver "^7.3.2"
sequelize-pool "^6.0.0"
toposort-class "^1.0.1"
uuid "^8.1.0"
validator "^13.6.0"
wkx "^0.5.0"
sequelize@^6.3.3: sequelize@^6.3.3:
version "6.6.5" version "6.6.5"
resolved "https://registry.npmjs.org/sequelize/-/sequelize-6.6.5.tgz#6f618e99f3df1fc81f28709e8a3139cec3ef1f0c" resolved "https://registry.npmjs.org/sequelize/-/sequelize-6.6.5.tgz#6f618e99f3df1fc81f28709e8a3139cec3ef1f0c"
@ -18685,6 +18904,16 @@ sprintf-js@~1.0.2:
resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
sqlite3@^5.0.2:
version "5.0.2"
resolved "https://registry.npmjs.org/sqlite3/-/sqlite3-5.0.2.tgz#00924adcc001c17686e0a6643b6cbbc2d3965083"
integrity sha512-1SdTNo+BVU211Xj1csWa8lV6KM0CtucDwRyA0VHl91wEH1Mgh7RxUpI4rVvG7OhHrzCSGaVyW5g8vKvlrk9DJA==
dependencies:
node-addon-api "^3.0.0"
node-pre-gyp "^0.11.0"
optionalDependencies:
node-gyp "3.x"
sqlstring@^2.3.2: sqlstring@^2.3.2:
version "2.3.2" version "2.3.2"
resolved "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz#cdae7169389a1375b18e885f2e60b3e460809514" resolved "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz#cdae7169389a1375b18e885f2e60b3e460809514"
@ -19229,6 +19458,28 @@ tapable@^1.0.0:
resolved "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" resolved "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
tar@^2.0.0:
version "2.2.2"
resolved "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40"
integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==
dependencies:
block-stream "*"
fstream "^1.0.12"
inherits "2"
tar@^4:
version "4.4.19"
resolved "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3"
integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==
dependencies:
chownr "^1.1.4"
fs-minipass "^1.2.7"
minipass "^2.9.0"
minizlib "^1.3.3"
mkdirp "^0.5.5"
safe-buffer "^5.2.1"
yallist "^3.1.1"
tar@^4.4.10, tar@^4.4.12, tar@^4.4.8: tar@^4.4.10, tar@^4.4.12, tar@^4.4.8:
version "4.4.17" version "4.4.17"
resolved "https://registry.npmjs.org/tar/-/tar-4.4.17.tgz#44be5e3fa8353ee1d11db3b1401561223a5c3985" resolved "https://registry.npmjs.org/tar/-/tar-4.4.17.tgz#44be5e3fa8353ee1d11db3b1401561223a5c3985"
@ -20599,7 +20850,7 @@ warning@^4.0.1, warning@^4.0.3:
dependencies: dependencies:
loose-envify "^1.0.0" loose-envify "^1.0.0"
wcwidth@^1.0.0: wcwidth@^1.0.0, wcwidth@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=
@ -20699,7 +20950,7 @@ which-module@^2.0.0:
resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
which@^1.2.9, which@^1.3.0, which@^1.3.1: which@1, which@^1.2.9, which@^1.3.0, which@^1.3.1:
version "1.3.1" version "1.3.1"
resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==