fix: update inherited collection performance issue (#3070)
This commit is contained in:
parent
19bad669af
commit
c81fb46071
62
packages/core/database/src/__tests__/sync.test.ts
Normal file
62
packages/core/database/src/__tests__/sync.test.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import { Database, mockDatabase } from '@nocobase/database';
|
||||
|
||||
describe('sync', () => {
|
||||
let db: Database;
|
||||
|
||||
beforeEach(async () => {
|
||||
db = mockDatabase({
|
||||
logging: console.log,
|
||||
});
|
||||
|
||||
await db.clean({ drop: true });
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await db.close();
|
||||
});
|
||||
|
||||
it('should not sync id fields when inherits not changed', async () => {
|
||||
if (!db.inDialect('postgres')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Parent = db.collection({
|
||||
name: 'parent',
|
||||
fields: [
|
||||
{
|
||||
type: 'string',
|
||||
name: 'name',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const fn = jest.fn();
|
||||
|
||||
const Child = db.collection({
|
||||
name: 'child',
|
||||
inherits: ['parent'],
|
||||
fields: [
|
||||
{
|
||||
type: 'string',
|
||||
name: 'name',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(await Child.existsInDb()).toBeFalsy();
|
||||
|
||||
await db.sync();
|
||||
|
||||
expect(await Child.existsInDb()).toBeTruthy();
|
||||
|
||||
Child.setField('age', {
|
||||
type: 'integer',
|
||||
});
|
||||
|
||||
await db.sync({});
|
||||
|
||||
const tableColumns = await db.sequelize.getQueryInterface().describeTable(Child.getTableNameWithSchema());
|
||||
|
||||
expect(tableColumns).toHaveProperty('age');
|
||||
});
|
||||
});
|
@ -20,106 +20,108 @@ export class SyncRunner {
|
||||
|
||||
if (!parents) {
|
||||
throw new Error(
|
||||
`Inherit model ${
|
||||
inheritedCollection.name
|
||||
} can't be created without parents, parents option is ${lodash
|
||||
`Inherit model ${inheritedCollection.name} can't be created without parents, parents option is ${lodash
|
||||
.castArray(inheritedCollection.options.inherits)
|
||||
.join(', ')}`,
|
||||
);
|
||||
}
|
||||
|
||||
const tableName = inheritedCollection.getTableNameWithSchema();
|
||||
|
||||
const attributes = model.tableAttributes;
|
||||
|
||||
const childAttributes = lodash.pickBy(attributes, (value) => {
|
||||
return !value.inherit;
|
||||
});
|
||||
|
||||
let maxSequenceVal = 0;
|
||||
let maxSequenceName;
|
||||
if (
|
||||
!(await inheritedCollection.existsInDb({
|
||||
transaction,
|
||||
}))
|
||||
) {
|
||||
let maxSequenceVal = 0;
|
||||
let maxSequenceName;
|
||||
|
||||
// find max sequence
|
||||
if (childAttributes.id && childAttributes.id.autoIncrement) {
|
||||
for (const parent of parents) {
|
||||
const sequenceNameResult = await queryInterface.sequelize.query(
|
||||
`SELECT column_default
|
||||
// find max sequence
|
||||
if (childAttributes.id && childAttributes.id.autoIncrement) {
|
||||
for (const parent of parents) {
|
||||
const sequenceNameResult = await queryInterface.sequelize.query(
|
||||
`SELECT column_default
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = '${parent.model.tableName}'
|
||||
and table_schema = '${parent.collectionSchema()}'
|
||||
and "column_name" = 'id';`,
|
||||
{
|
||||
transaction,
|
||||
},
|
||||
);
|
||||
{
|
||||
transaction,
|
||||
},
|
||||
);
|
||||
|
||||
if (!sequenceNameResult[0].length) {
|
||||
continue;
|
||||
}
|
||||
if (!sequenceNameResult[0].length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const columnDefault = sequenceNameResult[0][0]['column_default'];
|
||||
const columnDefault = sequenceNameResult[0][0]['column_default'];
|
||||
|
||||
if (!columnDefault) {
|
||||
throw new Error(`Can't find sequence name of parent collection ${parent.options.name}`);
|
||||
}
|
||||
if (!columnDefault) {
|
||||
throw new Error(`Can't find sequence name of parent collection ${parent.options.name}`);
|
||||
}
|
||||
|
||||
const regex = new RegExp(/nextval\('(.*)'::regclass\)/);
|
||||
const match = regex.exec(columnDefault);
|
||||
const regex = new RegExp(/nextval\('(.*)'::regclass\)/);
|
||||
const match = regex.exec(columnDefault);
|
||||
|
||||
const sequenceName = match[1];
|
||||
const sequenceCurrentValResult = await queryInterface.sequelize.query(
|
||||
`select last_value
|
||||
const sequenceName = match[1];
|
||||
const sequenceCurrentValResult = await queryInterface.sequelize.query(
|
||||
`select last_value
|
||||
from ${sequenceName}`,
|
||||
{
|
||||
transaction,
|
||||
},
|
||||
);
|
||||
{
|
||||
transaction,
|
||||
},
|
||||
);
|
||||
|
||||
const sequenceCurrentVal = parseInt(sequenceCurrentValResult[0][0]['last_value']);
|
||||
const sequenceCurrentVal = parseInt(sequenceCurrentValResult[0][0]['last_value']);
|
||||
|
||||
if (sequenceCurrentVal > maxSequenceVal) {
|
||||
maxSequenceName = sequenceName;
|
||||
maxSequenceVal = sequenceCurrentVal;
|
||||
if (sequenceCurrentVal > maxSequenceVal) {
|
||||
maxSequenceName = sequenceName;
|
||||
maxSequenceVal = sequenceCurrentVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await this.createTable(tableName, childAttributes, options, model, parents);
|
||||
await this.createTable(tableName, childAttributes, options, model, parents);
|
||||
|
||||
// if we have max sequence, set it to child table
|
||||
if (maxSequenceName) {
|
||||
const parentsDeep = Array.from(db.inheritanceMap.getParents(inheritedCollection.name)).map((parent) =>
|
||||
db.getCollection(parent).getTableNameWithSchema(),
|
||||
);
|
||||
// if we have max sequence, set it to child table
|
||||
if (maxSequenceName) {
|
||||
const parentsDeep = Array.from(db.inheritanceMap.getParents(inheritedCollection.name)).map((parent) =>
|
||||
db.getCollection(parent).getTableNameWithSchema(),
|
||||
);
|
||||
|
||||
const sequenceTables = [...parentsDeep, tableName];
|
||||
const sequenceTables = [...parentsDeep, tableName];
|
||||
|
||||
for (const sequenceTable of sequenceTables) {
|
||||
const tableName = sequenceTable.tableName;
|
||||
const schemaName = sequenceTable.schema;
|
||||
for (const sequenceTable of sequenceTables) {
|
||||
const tableName = sequenceTable.tableName;
|
||||
const schemaName = sequenceTable.schema;
|
||||
|
||||
const idColumnSql = `SELECT column_name
|
||||
const idColumnSql = `SELECT column_name
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = '${tableName}'
|
||||
and column_name = 'id'
|
||||
and table_schema = '${schemaName}';
|
||||
`;
|
||||
|
||||
const idColumnQuery = await queryInterface.sequelize.query(idColumnSql, {
|
||||
transaction,
|
||||
});
|
||||
|
||||
if (idColumnQuery[0].length == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
await queryInterface.sequelize.query(
|
||||
`alter table ${db.utils.quoteTable(sequenceTable)}
|
||||
alter column id set default nextval('${maxSequenceName}')`,
|
||||
{
|
||||
const idColumnQuery = await queryInterface.sequelize.query(idColumnSql, {
|
||||
transaction,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
if (idColumnQuery[0].length == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
await queryInterface.sequelize.query(
|
||||
`alter table ${db.utils.quoteTable(sequenceTable)}
|
||||
alter column id set default nextval('${maxSequenceName}')`,
|
||||
{
|
||||
transaction,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user