mirror of
https://gitee.com/nocobase/nocobase.git
synced 2024-12-04 05:08:42 +08:00
refactor: mockDatabase
This commit is contained in:
parent
0d0acba357
commit
c5f639338f
@ -1,6 +1,6 @@
|
|||||||
import { Collection } from '../collection';
|
import { Collection } from '../collection';
|
||||||
import { Database } from '../database';
|
import { Database } from '../database';
|
||||||
import { generatePrefixByPath, mockDatabase } from './index';
|
import { mockDatabase } from './index';
|
||||||
|
|
||||||
test('collection disable authGenId', async () => {
|
test('collection disable authGenId', async () => {
|
||||||
const db = mockDatabase();
|
const db = mockDatabase();
|
||||||
@ -91,7 +91,7 @@ describe('collection sync', () => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
await collection.sync();
|
await collection.sync();
|
||||||
const tableFields = await (<any>collection.model).queryInterface.describeTable(`${generatePrefixByPath()}_users`);
|
const tableFields = await (<any>collection.model).queryInterface.describeTable(`${db.getTablePrefix()}users`);
|
||||||
|
|
||||||
expect(tableFields).toHaveProperty('firstName');
|
expect(tableFields).toHaveProperty('firstName');
|
||||||
expect(tableFields).toHaveProperty('lastName');
|
expect(tableFields).toHaveProperty('lastName');
|
||||||
@ -114,7 +114,7 @@ describe('collection sync', () => {
|
|||||||
|
|
||||||
const model = collection.model;
|
const model = collection.model;
|
||||||
|
|
||||||
const tableFields = await (<any>model).queryInterface.describeTable(`${generatePrefixByPath()}_posts`);
|
const tableFields = await (<any>model).queryInterface.describeTable(`${db.getTablePrefix()}posts`);
|
||||||
|
|
||||||
expect(tableFields['user_id']).toBeUndefined();
|
expect(tableFields['user_id']).toBeUndefined();
|
||||||
});
|
});
|
||||||
@ -143,7 +143,7 @@ describe('collection sync', () => {
|
|||||||
|
|
||||||
const model = collection.model;
|
const model = collection.model;
|
||||||
await collection.sync();
|
await collection.sync();
|
||||||
const tableFields = await (<any>model).queryInterface.describeTable(`${generatePrefixByPath()}_posts_tags`);
|
const tableFields = await (<any>model).queryInterface.describeTable(`${db.getTablePrefix()}posts_tags`);
|
||||||
expect(tableFields['postId']).toBeDefined();
|
expect(tableFields['postId']).toBeDefined();
|
||||||
expect(tableFields['tagId']).toBeDefined();
|
expect(tableFields['tagId']).toBeDefined();
|
||||||
});
|
});
|
||||||
@ -184,13 +184,13 @@ test.skip('update collection options', async () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(collection.model.getTableName()).toEqual(`${generatePrefixByPath()}_posts`);
|
expect(collection.model.getTableName()).toEqual(`${db.getTablePrefix()}posts`);
|
||||||
|
|
||||||
collection.updateOptions({
|
collection.updateOptions({
|
||||||
name: 'articles',
|
name: 'articles',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(collection.model.getTableName()).toEqual(`${generatePrefixByPath()}_articles`);
|
expect(collection.model.getTableName()).toEqual(`${db.getTablePrefix()}articles`);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('collection with association', async () => {
|
test('collection with association', async () => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { mockDatabase } from './index';
|
|
||||||
import FilterParser from '../filter-parser';
|
|
||||||
import { Op } from 'sequelize';
|
import { Op } from 'sequelize';
|
||||||
import { Database } from '../database';
|
import { Database } from '../database';
|
||||||
|
import FilterParser from '../filter-parser';
|
||||||
|
import { mockDatabase } from './index';
|
||||||
|
|
||||||
test('filter item by string', async () => {
|
test('filter item by string', async () => {
|
||||||
const database = mockDatabase();
|
const database = mockDatabase();
|
||||||
|
@ -1,94 +1 @@
|
|||||||
import { uid } from '@nocobase/utils';
|
export { mockDatabase } from '../mock-database';
|
||||||
import merge from 'deepmerge';
|
|
||||||
import { Sequelize } from 'sequelize';
|
|
||||||
import { Database, DatabaseOptions } from '../database';
|
|
||||||
|
|
||||||
export function generatePrefixByPath() {
|
|
||||||
const { id } = require.main;
|
|
||||||
const key = id
|
|
||||||
.replace(`${process.env.PWD}/packages`, '')
|
|
||||||
.replace(/src\/__tests__/g, '')
|
|
||||||
.replace('.test.ts', '')
|
|
||||||
.replace(/[^\w]/g, '_')
|
|
||||||
.replace(/_+/g, '_');
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getConfig(config: any = {}, options?: any): DatabaseOptions {
|
|
||||||
if (process.env.DB_DIALECT === 'sqlite') {
|
|
||||||
const defaults = {
|
|
||||||
dialect: process.env.DB_DIALECT as any,
|
|
||||||
storage: ':memory:',
|
|
||||||
logging: process.env.DB_LOG_SQL === 'on' ? console.log : false,
|
|
||||||
// sync: {
|
|
||||||
// force: true,
|
|
||||||
// },
|
|
||||||
hooks: {
|
|
||||||
beforeDefine(model, options) {
|
|
||||||
options.tableName = `${generatePrefixByPath()}_${
|
|
||||||
options.tableName || options.modelName || options.name.plural
|
|
||||||
}`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
return merge(defaults, config, options);
|
|
||||||
}
|
|
||||||
const database = `mock_${uid()}`;
|
|
||||||
let dbExists = false;
|
|
||||||
const defaults = {
|
|
||||||
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,
|
|
||||||
logging: process.env.DB_LOG_SQL === 'on' ? console.log : false,
|
|
||||||
dialectOptions: {
|
|
||||||
charset: 'utf8mb4',
|
|
||||||
collate: 'utf8mb4_unicode_ci',
|
|
||||||
},
|
|
||||||
hooks: {
|
|
||||||
beforeDefine(model, options) {
|
|
||||||
options.tableName = `${generatePrefixByPath()}_${
|
|
||||||
options.tableName || options.modelName || options.name.plural
|
|
||||||
}`;
|
|
||||||
},
|
|
||||||
async beforeSync({ sequelize }: any) {
|
|
||||||
if (config.database) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (dbExists) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
const db = new Sequelize({
|
|
||||||
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,
|
|
||||||
logging: process.env.DB_LOG_SQL === 'on' ? console.log : false,
|
|
||||||
dialectOptions: {
|
|
||||||
charset: 'utf8mb4',
|
|
||||||
collate: 'utf8mb4_unicode_ci',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
await db.query(`CREATE DATABASE "${database}";`);
|
|
||||||
await db.close();
|
|
||||||
sequelize.options.database = database;
|
|
||||||
sequelize.config.database = database;
|
|
||||||
const ConnectionManager = sequelize.dialect.connectionManager.constructor;
|
|
||||||
const connectionManager = new ConnectionManager(sequelize.dialect, sequelize);
|
|
||||||
sequelize.dialect.connectionManager = connectionManager;
|
|
||||||
sequelize.connectionManager = connectionManager;
|
|
||||||
dbExists = true;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
return merge(defaults, config, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function mockDatabase(options?: DatabaseOptions): Database {
|
|
||||||
return new Database(getConfig(options));
|
|
||||||
}
|
|
||||||
|
@ -31,7 +31,11 @@ interface MapOf<T> {
|
|||||||
[key: string]: T;
|
[key: string]: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DatabaseOptions = Options | Sequelize;
|
export interface IDatabaseOptions extends Options {
|
||||||
|
tablePrefix?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DatabaseOptions = IDatabaseOptions | Sequelize;
|
||||||
|
|
||||||
interface RegisterOperatorsContext {
|
interface RegisterOperatorsContext {
|
||||||
db?: Database;
|
db?: Database;
|
||||||
@ -48,6 +52,7 @@ type OperatorFunc = (value: any, ctx?: RegisterOperatorsContext) => any;
|
|||||||
export class Database extends EventEmitter implements AsyncEmitter {
|
export class Database extends EventEmitter implements AsyncEmitter {
|
||||||
sequelize: Sequelize;
|
sequelize: Sequelize;
|
||||||
fieldTypes = new Map();
|
fieldTypes = new Map();
|
||||||
|
options: IDatabaseOptions;
|
||||||
models = new Map<string, ModelCtor<any>>();
|
models = new Map<string, ModelCtor<any>>();
|
||||||
repositories = new Map<string, RepositoryType>();
|
repositories = new Map<string, RepositoryType>();
|
||||||
operators = new Map();
|
operators = new Map();
|
||||||
@ -66,6 +71,7 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|||||||
this.sequelize = options;
|
this.sequelize = options;
|
||||||
} else {
|
} else {
|
||||||
this.sequelize = new Sequelize(options);
|
this.sequelize = new Sequelize(options);
|
||||||
|
this.options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.collections = new Map();
|
this.collections = new Map();
|
||||||
@ -115,6 +121,10 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|||||||
return collection;
|
return collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTablePrefix() {
|
||||||
|
return this.options.tablePrefix || '';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get exists collection by its name
|
* get exists collection by its name
|
||||||
* @param name
|
* @param name
|
||||||
|
@ -4,6 +4,7 @@ export * from './database';
|
|||||||
export { Database as default } from './database';
|
export { Database as default } from './database';
|
||||||
export * from './fields';
|
export * from './fields';
|
||||||
export * from './magic-attribute-model';
|
export * from './magic-attribute-model';
|
||||||
|
export * from './mock-database';
|
||||||
export * from './relation-repository/belongs-to-many-repository';
|
export * from './relation-repository/belongs-to-many-repository';
|
||||||
export * from './relation-repository/belongs-to-repository';
|
export * from './relation-repository/belongs-to-repository';
|
||||||
export * from './relation-repository/hasmany-repository';
|
export * from './relation-repository/hasmany-repository';
|
||||||
@ -12,4 +13,3 @@ export * from './relation-repository/single-relation-repository';
|
|||||||
export * from './repository';
|
export * from './repository';
|
||||||
export * from './update-associations';
|
export * from './update-associations';
|
||||||
|
|
||||||
|
|
||||||
|
37
packages/database/src/mock-database.ts
Normal file
37
packages/database/src/mock-database.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { merge, uid } from '@nocobase/utils';
|
||||||
|
import { resolve } from 'path';
|
||||||
|
import { Database, IDatabaseOptions } from './database';
|
||||||
|
|
||||||
|
export class MockDatabase extends Database {
|
||||||
|
constructor(options: IDatabaseOptions) {
|
||||||
|
super({
|
||||||
|
storage: ':memory:',
|
||||||
|
tablePrefix: `mock_${uid(6)}_`,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
this.sequelize.beforeDefine((model, opts) => {
|
||||||
|
opts.tableName = `${this.getTablePrefix()}${opts.tableName || opts.modelName || opts.name.plural}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getConfigByEnv() {
|
||||||
|
return {
|
||||||
|
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,
|
||||||
|
dialect: process.env.DB_DIALECT,
|
||||||
|
logging: process.env.DB_LOG_SQL === 'on' ? console.log : false,
|
||||||
|
storage: process.env.DB_STORAGE ? resolve(process.cwd(), process.env.DB_STORAGE) : ':memory:',
|
||||||
|
dialectOptions: {
|
||||||
|
charset: 'utf8mb4',
|
||||||
|
collate: 'utf8mb4_unicode_ci',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mockDatabase(options: IDatabaseOptions = {}): MockDatabase {
|
||||||
|
return new MockDatabase(merge(getConfigByEnv(), options));
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import { ACL } from '@nocobase/acl';
|
import { ACL } from '@nocobase/acl';
|
||||||
import { registerActions } from '@nocobase/actions';
|
import { registerActions } from '@nocobase/actions';
|
||||||
import Database, { CleanOptions, CollectionOptions, DatabaseOptions, SyncOptions } from '@nocobase/database';
|
import Database, { CleanOptions, CollectionOptions, IDatabaseOptions, SyncOptions } from '@nocobase/database';
|
||||||
import Resourcer, { ResourceOptions } from '@nocobase/resourcer';
|
import Resourcer, { ResourceOptions } from '@nocobase/resourcer';
|
||||||
import { applyMixins, AsyncEmitter } from '@nocobase/utils';
|
import { applyMixins, AsyncEmitter } from '@nocobase/utils';
|
||||||
import { Command, CommandOptions } from 'commander';
|
import { Command, CommandOptions } from 'commander';
|
||||||
@ -18,7 +18,7 @@ export interface ResourcerOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ApplicationOptions {
|
export interface ApplicationOptions {
|
||||||
database?: DatabaseOptions;
|
database?: IDatabaseOptions | Database;
|
||||||
resourcer?: ResourcerOptions;
|
resourcer?: ResourcerOptions;
|
||||||
bodyParser?: any;
|
bodyParser?: any;
|
||||||
cors?: any;
|
cors?: any;
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
import { mockDatabase } from '../';
|
|
||||||
|
|
||||||
describe('mock databasea', () => {
|
|
||||||
it('mock databasea', async () => {
|
|
||||||
const db = mockDatabase();
|
|
||||||
db.collection({
|
|
||||||
name: 'tests',
|
|
||||||
fields: [{ type: 'string', name: 'name' }],
|
|
||||||
});
|
|
||||||
expect(db.getCollection('tests').model.getTableName()).toBe('_test_mockDatabase_tests');
|
|
||||||
await db.sync();
|
|
||||||
await db.close();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,34 +0,0 @@
|
|||||||
import { mockServer, MockServer } from '../';
|
|
||||||
|
|
||||||
describe('mock server', () => {
|
|
||||||
let api: MockServer;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
api = mockServer({
|
|
||||||
dataWrapping: false,
|
|
||||||
});
|
|
||||||
api.resourcer.registerActionHandlers({
|
|
||||||
list: async (ctx, next) => {
|
|
||||||
ctx.body = [1, 2];
|
|
||||||
await next();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
api.resourcer.define({
|
|
||||||
name: 'test',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
return api.destroy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('agent', async () => {
|
|
||||||
const response = await api.agent().get('/test');
|
|
||||||
expect(response.body).toEqual([1, 2]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('resource', async () => {
|
|
||||||
const response = await api.agent().resource('test').list();
|
|
||||||
expect(response.body).toEqual([1, 2]);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,2 +1,3 @@
|
|||||||
export * from './mockDatabase';
|
export { mockDatabase } from '@nocobase/database';
|
||||||
export * from './mockServer';
|
export * from './mockServer';
|
||||||
|
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
import merge from 'deepmerge';
|
|
||||||
import Database, { DatabaseOptions } from '@nocobase/database';
|
|
||||||
|
|
||||||
export function generatePrefixByPath() {
|
|
||||||
const { id } = require.main;
|
|
||||||
const key = id
|
|
||||||
.replace(`${process.env.PWD}/packages`, '')
|
|
||||||
.replace(/src\/__tests__/g, '')
|
|
||||||
.replace('.test.ts', '')
|
|
||||||
.replace(/[^\w]/g, '_')
|
|
||||||
.replace(/_+/g, '_');
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getConfig(config = {}, options?: any): DatabaseOptions {
|
|
||||||
return merge(
|
|
||||||
{
|
|
||||||
username: process.env.DB_USER,
|
|
||||||
password: process.env.DB_PASSWORD,
|
|
||||||
storage: process.env.DB_STORAGE,
|
|
||||||
database: process.env.DB_DATABASE,
|
|
||||||
host: process.env.DB_HOST,
|
|
||||||
port: process.env.DB_PORT,
|
|
||||||
dialect: process.env.DB_DIALECT,
|
|
||||||
logging: process.env.DB_LOG_SQL === 'on',
|
|
||||||
sync: {
|
|
||||||
force: true,
|
|
||||||
alter: {
|
|
||||||
drop: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
hooks: {
|
|
||||||
beforeDefine(model, options) {
|
|
||||||
options.tableName = `${generatePrefixByPath()}_${options.tableName || options.name.plural}`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
config || {},
|
|
||||||
options,
|
|
||||||
) as any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function mockDatabase(options?: DatabaseOptions): Database {
|
|
||||||
return new Database(getConfig(options));
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
|
import { mockDatabase } from '@nocobase/database';
|
||||||
|
import Application, { ApplicationOptions } from '@nocobase/server';
|
||||||
import qs from 'qs';
|
import qs from 'qs';
|
||||||
import supertest, { SuperAgentTest } from 'supertest';
|
import supertest, { SuperAgentTest } from 'supertest';
|
||||||
import Application, { ApplicationOptions } from '@nocobase/server';
|
|
||||||
import { getConfig } from './mockDatabase';
|
|
||||||
|
|
||||||
interface ActionParams {
|
interface ActionParams {
|
||||||
filterByTk?: any;
|
filterByTk?: any;
|
||||||
@ -123,10 +123,11 @@ export class MockServer extends Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mockServer(options?: ApplicationOptions) {
|
export function mockServer(options: ApplicationOptions = {}) {
|
||||||
|
const database = mockDatabase((<any>options?.database) || {});
|
||||||
return new MockServer({
|
return new MockServer({
|
||||||
...options,
|
...options,
|
||||||
database: getConfig(options?.database),
|
database,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user