refactor: optimze view

This commit is contained in:
aaaaaajie 2025-04-11 09:45:44 +08:00
parent 11d0ddcd14
commit 376d411918
7 changed files with 66 additions and 33 deletions

View File

@ -343,6 +343,14 @@ export class Database extends EventEmitter implements AsyncEmitter {
return this._instanceId; return this._instanceId;
} }
get dialectClass() {
return Database.getDialect(this.options.dialect);
}
get schema() {
return this.options.schema || this.dialectClass.getQueryInterface(this).defaultSchemaName;
}
/** /**
* @internal * @internal
*/ */

View File

@ -290,7 +290,7 @@ export class EagerLoadingTree {
} }
// find all ids // find all ids
const ids = (await node.model.findAll()).map((row) => { const ids = (await node.model.findAll(options)).map((row) => {
return { row, pk: row[primaryKeyField] }; return { row, pk: row[primaryKeyField] };
}); });

View File

@ -15,7 +15,7 @@ import { ModelStatic, Transaction } from 'sequelize';
export default class PostgresQueryInterface extends QueryInterface { export default class PostgresQueryInterface extends QueryInterface {
constructor(db) { constructor(db) {
super(db); super(db, { defaultSchemaName: 'public' });
} }
async setAutoIncrementVal(options: { async setAutoIncrementVal(options: {

View File

@ -11,6 +11,7 @@ import {
ColumnDescription, ColumnDescription,
ModelStatic, ModelStatic,
QueryInterfaceDropTableOptions, QueryInterfaceDropTableOptions,
QueryInterfaceOptions,
QueryInterface as SequelizeQueryInterface, QueryInterface as SequelizeQueryInterface,
TableName, TableName,
Transaction, Transaction,
@ -56,6 +57,7 @@ export type ChangeColumnAction = (typeof ChangeColumnAction)[keyof typeof Change
type QueryInterfaceConfig = { type QueryInterfaceConfig = {
changeColumnMode?: 'default' | 'sequelize'; changeColumnMode?: 'default' | 'sequelize';
defaultSchemaName?: string;
}; };
export interface RemoveColumnOptions { export interface RemoveColumnOptions {
@ -74,7 +76,7 @@ export default abstract class QueryInterface {
config?: QueryInterfaceConfig, config?: QueryInterfaceConfig,
) { ) {
this.sequelizeQueryInterface = db.sequelize.getQueryInterface(); this.sequelizeQueryInterface = db.sequelize.getQueryInterface();
this.config = config || { changeColumnMode: 'default' }; this.config = { changeColumnMode: 'default', ...(config || {}) };
} }
abstract collectionTableExists(collection: Collection, options?: Transactionable): Promise<boolean>; abstract collectionTableExists(collection: Collection, options?: Transactionable): Promise<boolean>;
@ -101,6 +103,10 @@ export default abstract class QueryInterface {
abstract afterRemoveColumn(options: RemoveColumnOptions): Promise<void>; abstract afterRemoveColumn(options: RemoveColumnOptions): Promise<void>;
get defaultSchemaName() {
return this.config.defaultSchemaName;
}
async dropAll(options) { async dropAll(options) {
if (options.drop !== true) return; if (options.drop !== true) return;

View File

@ -252,7 +252,7 @@ describe('collections repository', () => {
expect(response1.body.data.length).toBe(2); expect(response1.body.data.length).toBe(2);
}); });
it.only('case 7', async () => { it('case 7', async () => {
const response = await agent.resource('posts').create({ const response = await agent.resource('posts').create({
values: { values: {
tags: [ tags: [

View File

@ -40,21 +40,29 @@ describe('view collection', () => {
const viewSQL = (() => { const viewSQL = (() => {
if (app.db.inDialect('sqlite')) { if (app.db.inDialect('sqlite')) {
return `CREATE VIEW ${testViewName} AS WITH RECURSIVE numbers(n) AS ( return `CREATE VIEW ${testViewName} AS WITH RECURSIVE numbers(n) AS (
SELECT CAST(1 AS INTEGER) SELECT CAST(1 AS INTEGER)
UNION ALL UNION ALL
SELECT CAST(1 + n AS INTEGER) FROM numbers WHERE n < 20 SELECT CAST(1 + n AS INTEGER) FROM numbers WHERE n < 20
) )
SELECT * FROM numbers; SELECT * FROM numbers;
`; `;
} else if (app.db.inDialect('mssql')) {
return `CREATE VIEW ${testViewName} AS WITH numbers(n) AS (
SELECT 1
UNION ALL
SELECT n + 1 FROM numbers WHERE n < 20
)
SELECT * FROM numbers;
`;
} else {
return `CREATE VIEW ${testViewName} AS WITH RECURSIVE numbers(n) AS (
SELECT 1
UNION ALL
SELECT n + 1 FROM numbers WHERE n < 20
)
SELECT * FROM numbers;
`;
} }
return `CREATE VIEW ${testViewName} AS WITH RECURSIVE numbers(n) AS (
SELECT 1
UNION ALL
SELECT n + 1 FROM numbers WHERE n < 20
)
SELECT * FROM numbers;
`;
})(); })();
await app.db.sequelize.query(viewSQL); await app.db.sequelize.query(viewSQL);
}); });
@ -63,6 +71,15 @@ SELECT * FROM numbers;
await app.destroy(); await app.destroy();
}); });
function getSchema() {
if (app.db.options.dialect === 'mssql') {
return 'dbo';
}
if (app.db.options.dialect === 'postgres') {
return 'public';
}
}
it('should support preview field with getter', async () => { it('should support preview field with getter', async () => {
class TestField extends Field { class TestField extends Field {
constructor(options: any, context: any) { constructor(options: any, context: any) {
@ -139,7 +156,7 @@ SELECT * FROM numbers;
values: { values: {
name: testViewName, name: testViewName,
view: true, view: true,
schema: app.db.inDialect('postgres') ? 'public' : undefined, schema: getSchema(),
fields: [ fields: [
{ {
name: 'numbers', name: 'numbers',
@ -168,7 +185,7 @@ SELECT * FROM numbers;
it('should list views fields', async () => { it('should list views fields', async () => {
const response = await agent.resource('dbViews').get({ const response = await agent.resource('dbViews').get({
filterByTk: testViewName, filterByTk: testViewName,
schema: 'public', schema: getSchema(),
}); });
expect(response.status).toBe(200); expect(response.status).toBe(200);
@ -196,6 +213,10 @@ SELECT * FROM numbers;
if (app.db.inDialect('postgres')) { if (app.db.inDialect('postgres')) {
return `CREATE VIEW ${jsonViewName} AS SELECT '{"a": 1}'::json as json_field`; return `CREATE VIEW ${jsonViewName} AS SELECT '{"a": 1}'::json as json_field`;
} }
if (app.db.inDialect('mssql')) {
return `CREATE VIEW ${jsonViewName} AS
SELECT (SELECT 1 AS key1, 'abc' AS key2 FOR JSON PATH, WITHOUT_ARRAY_WRAPPER) as json_field`;
}
return `CREATE VIEW ${jsonViewName} AS SELECT JSON_OBJECT('key1', 1, 'key2', 'abc') as json_field`; return `CREATE VIEW ${jsonViewName} AS SELECT JSON_OBJECT('key1', 1, 'key2', 'abc') as json_field`;
})(); })();
@ -203,14 +224,14 @@ SELECT * FROM numbers;
const response = await agent.resource('dbViews').get({ const response = await agent.resource('dbViews').get({
filterByTk: jsonViewName, filterByTk: jsonViewName,
schema: app.db.inDialect('postgres') ? 'public' : undefined, schema: getSchema(),
}); });
expect(response.status).toBe(200); expect(response.status).toBe(200);
const data = response.body.data; const data = response.body.data;
const jsonField = data.fields.find((field) => field.name === 'json_field'); const jsonField = data.fields.find((field) => field.name === 'json_field');
expect(jsonField.type).toBe('json'); expect(jsonField.type).toBe(app.db.options.dialect === 'mssql' ? 'string' : 'json');
expect(jsonField.possibleTypes).toBeTruthy(); expect(jsonField.possibleTypes).toBeTruthy();
}); });
@ -250,7 +271,7 @@ SELECT * FROM numbers;
values: { values: {
name: viewName, name: viewName,
view: true, view: true,
schema: app.db.inDialect('postgres') ? 'public' : undefined, schema: getSchema(),
fields: [ fields: [
{ {
name: 'name', name: 'name',
@ -291,7 +312,7 @@ SELECT * FROM numbers;
expect(response2.statusCode).toBe(200); expect(response2.statusCode).toBe(200);
}); });
it('should list collections fields with source interface', async () => { it.only('should list collections fields with source interface', async () => {
await app.db.getRepository('collections').create({ await app.db.getRepository('collections').create({
values: { values: {
name: 'users', name: 'users',
@ -327,7 +348,7 @@ SELECT * FROM numbers;
values: { values: {
name: viewName, name: viewName,
view: true, view: true,
schema: app.db.inDialect('postgres') ? 'public' : undefined, schema: getSchema(),
fields: [ fields: [
{ {
name: 'name', name: 'name',
@ -440,7 +461,7 @@ SELECT * FROM numbers;
values: { values: {
name: viewName, name: viewName,
view: true, view: true,
schema: app.db.inDialect('postgres') ? 'public' : undefined, schema: getSchema(),
fields: [ fields: [
{ {
name: 'id', name: 'id',

View File

@ -78,16 +78,14 @@ export default {
}, },
async query(ctx, next) { async query(ctx, next) {
const { filterByTk, fieldTypes, schema = 'public', page = 1, pageSize = 10 } = ctx.action.params; const { filterByTk, fieldTypes, page = 1, pageSize = 10 } = ctx.action.params;
const schema = ctx.action.params.schema || ctx.app.db.options.schema || (ctx.app.db as Database).schema;
const offset = (page - 1) * pageSize; const offset = (page - 1) * pageSize;
const limit = 1 * pageSize; const limit = 1 * pageSize;
const table = schema ? ctx.app.db.utils.addSchema(filterByTk, schema) : filterByTk;
const sql = `SELECT * FROM ${ctx.app.db.utils.quoteTable(table)}`;
const sql = `SELECT * const rawValues = await ctx.app.db.sequelize.query(sql, { type: 'SELECT', limit, offset });
FROM ${ctx.app.db.utils.quoteTable(ctx.app.db.utils.addSchema(filterByTk, schema))} LIMIT ${limit}
OFFSET ${offset}`;
const rawValues = await ctx.app.db.sequelize.query(sql, { type: 'SELECT' });
if (fieldTypes) { if (fieldTypes) {
for (const raw of rawValues) { for (const raw of rawValues) {