mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-09 23:49:27 +08:00
refactor: optimze view
This commit is contained in:
parent
11d0ddcd14
commit
376d411918
@ -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
|
||||||
*/
|
*/
|
||||||
|
@ -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] };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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: {
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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: [
|
||||||
|
@ -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',
|
||||||
|
@ -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) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user