feat(cli): check database version before installation (#572)

* feat(cli): check database version before installation

* fix: log

* fix: fix bugs

* fix: postgres

* fix: run beforeInstall
This commit is contained in:
chenos 2022-07-04 13:41:07 +08:00 committed by GitHub
parent 4e9384bce2
commit ec7bc2bc8b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 66 additions and 4 deletions

View File

@ -76,7 +76,7 @@ yarn dev
Production Production
```bash ```bash
yarn start yarn start # Does not support running on win platform
``` ```
Note: For production, if the code has been modified, you need to execute `yarn build` and restart NocoBase. Note: For production, if the code has been modified, you need to execute `yarn build` and restart NocoBase.

View File

@ -56,7 +56,7 @@ Production
# Compile # Compile
yarn build yarn build
# Start # Start
yarn start yarn start # Does not support running on win platform
``` ```
## 7. Log in to NocoBase ## 7. Log in to NocoBase

View File

@ -83,7 +83,7 @@ yarn dev
生产环境 生产环境
```bash ```bash
yarn start yarn start # 暂不支持在 win 平台下运行
``` ```
注:生产环境,如果代码有修改,需要执行 `yarn build`,再重新启动 NocoBase。 注:生产环境,如果代码有修改,需要执行 `yarn build`,再重新启动 NocoBase。

View File

@ -58,7 +58,7 @@ yarn dev
# 编译 # 编译
yarn build yarn build
# 启动 # 启动
yarn start yarn start # 暂不支持在 win 平台下运行
``` ```
## 7. 登录 NocoBase ## 7. 登录 NocoBase

View File

@ -19,6 +19,12 @@ module.exports = (cli) => {
if (opts.port) { if (opts.port) {
process.env.APP_PORT = opts.port; process.env.APP_PORT = opts.port;
} }
if (process.platform === 'win32') {
console.log(
chalk.yellow(`It is not supported on win platform, please use \`${chalk.green('yarn dev')}\` instead`),
);
return;
}
if (process.argv.includes('-h') || process.argv.includes('--help')) { if (process.argv.includes('-h') || process.argv.includes('--help')) {
promptForTs(); promptForTs();
run('ts-node', [ run('ts-node', [

View File

@ -18,6 +18,7 @@
"flat": "^5.0.2", "flat": "^5.0.2",
"glob": "^7.1.6", "glob": "^7.1.6",
"mathjs": "^10.6.1", "mathjs": "^10.6.1",
"semver": "^7.3.7",
"sequelize": "^6.9.0", "sequelize": "^6.9.0",
"umzug": "^3.1.1" "umzug": "^3.1.1"
}, },

View File

@ -4,6 +4,7 @@ import { EventEmitter } from 'events';
import glob from 'glob'; import glob from 'glob';
import lodash from 'lodash'; import lodash from 'lodash';
import { basename, isAbsolute, resolve } from 'path'; import { basename, isAbsolute, resolve } from 'path';
import semver from 'semver';
import { import {
ModelCtor, ModelCtor,
Op, Op,
@ -65,6 +66,46 @@ export type AddMigrationsOptions = {
type OperatorFunc = (value: any, ctx?: RegisterOperatorsContext) => any; type OperatorFunc = (value: any, ctx?: RegisterOperatorsContext) => any;
class DatabaseVersion {
db: Database;
constructor(db: Database) {
this.db = db;
}
async satisfies(versions) {
const dialects = {
sqlite: {
sql: 'select sqlite_version() as version',
get: (v) => v,
},
mysql: {
sql: 'select version() as version',
get: (v) => v,
},
postgres: {
sql: 'select version() as version',
get: (v) => {
const keys = v.split(' ');
keys.shift();
return semver.minVersion(keys.shift()).version;
},
},
};
for (const dialect of Object.keys(dialects)) {
if (this.db.inDialect(dialect)) {
if (!versions?.[dialect]) {
return false;
}
const [result] = (await this.db.sequelize.query(dialects[dialect].sql)) as any;
console.log(`db version: ${dialects[dialect].get(result?.[0]?.version)}`);
return semver.satisfies(dialects[dialect].get(result?.[0]?.version), versions[dialect]);
}
}
return false;
}
}
export class Database extends EventEmitter implements AsyncEmitter { export class Database extends EventEmitter implements AsyncEmitter {
sequelize: Sequelize; sequelize: Sequelize;
migrator: Umzug; migrator: Umzug;
@ -79,12 +120,15 @@ export class Database extends EventEmitter implements AsyncEmitter {
modelCollection = new Map<ModelCtor<any>, Collection>(); modelCollection = new Map<ModelCtor<any>, Collection>();
modelHook: ModelHook; modelHook: ModelHook;
version: DatabaseVersion;
delayCollectionExtend = new Map<string, { collectionOptions: CollectionOptions; mergeOptions?: any }[]>(); delayCollectionExtend = new Map<string, { collectionOptions: CollectionOptions; mergeOptions?: any }[]>();
constructor(options: DatabaseOptions) { constructor(options: DatabaseOptions) {
super(); super();
this.version = new DatabaseVersion(this);
const opts = { const opts = {
sync: { sync: {
alter: { alter: {

View File

@ -323,6 +323,17 @@ export class Application<StateT = DefaultState, ContextT = DefaultContext> exten
async install(options: InstallOptions = {}) { async install(options: InstallOptions = {}) {
await this.emitAsync('beforeInstall', this, options); await this.emitAsync('beforeInstall', this, options);
const r = await this.db.version.satisfies({
mysql: '8.x',
sqlite: '3.x',
postgres: '>=10',
});
if (!r) {
console.log('The database only supports MySQL 8.x, SQLite 3.x and PostgreSQL 10+');
return;
}
if (options?.clean) { if (options?.clean) {
await this.db.clean(isBoolean(options.clean) ? { drop: options.clean } : options.clean); await this.db.clean(isBoolean(options.clean) ? { drop: options.clean } : options.clean);
} }