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) {
|
if (!parents) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Inherit model ${
|
`Inherit model ${inheritedCollection.name} can't be created without parents, parents option is ${lodash
|
||||||
inheritedCollection.name
|
|
||||||
} can't be created without parents, parents option is ${lodash
|
|
||||||
.castArray(inheritedCollection.options.inherits)
|
.castArray(inheritedCollection.options.inherits)
|
||||||
.join(', ')}`,
|
.join(', ')}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tableName = inheritedCollection.getTableNameWithSchema();
|
const tableName = inheritedCollection.getTableNameWithSchema();
|
||||||
|
|
||||||
const attributes = model.tableAttributes;
|
const attributes = model.tableAttributes;
|
||||||
|
|
||||||
const childAttributes = lodash.pickBy(attributes, (value) => {
|
const childAttributes = lodash.pickBy(attributes, (value) => {
|
||||||
return !value.inherit;
|
return !value.inherit;
|
||||||
});
|
});
|
||||||
|
|
||||||
let maxSequenceVal = 0;
|
if (
|
||||||
let maxSequenceName;
|
!(await inheritedCollection.existsInDb({
|
||||||
|
transaction,
|
||||||
|
}))
|
||||||
|
) {
|
||||||
|
let maxSequenceVal = 0;
|
||||||
|
let maxSequenceName;
|
||||||
|
|
||||||
// find max sequence
|
// find max sequence
|
||||||
if (childAttributes.id && childAttributes.id.autoIncrement) {
|
if (childAttributes.id && childAttributes.id.autoIncrement) {
|
||||||
for (const parent of parents) {
|
for (const parent of parents) {
|
||||||
const sequenceNameResult = await queryInterface.sequelize.query(
|
const sequenceNameResult = await queryInterface.sequelize.query(
|
||||||
`SELECT column_default
|
`SELECT column_default
|
||||||
FROM information_schema.columns
|
FROM information_schema.columns
|
||||||
WHERE table_name = '${parent.model.tableName}'
|
WHERE table_name = '${parent.model.tableName}'
|
||||||
and table_schema = '${parent.collectionSchema()}'
|
and table_schema = '${parent.collectionSchema()}'
|
||||||
and "column_name" = 'id';`,
|
and "column_name" = 'id';`,
|
||||||
{
|
{
|
||||||
transaction,
|
transaction,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!sequenceNameResult[0].length) {
|
if (!sequenceNameResult[0].length) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const columnDefault = sequenceNameResult[0][0]['column_default'];
|
const columnDefault = sequenceNameResult[0][0]['column_default'];
|
||||||
|
|
||||||
if (!columnDefault) {
|
if (!columnDefault) {
|
||||||
throw new Error(`Can't find sequence name of parent collection ${parent.options.name}`);
|
throw new Error(`Can't find sequence name of parent collection ${parent.options.name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const regex = new RegExp(/nextval\('(.*)'::regclass\)/);
|
const regex = new RegExp(/nextval\('(.*)'::regclass\)/);
|
||||||
const match = regex.exec(columnDefault);
|
const match = regex.exec(columnDefault);
|
||||||
|
|
||||||
const sequenceName = match[1];
|
const sequenceName = match[1];
|
||||||
const sequenceCurrentValResult = await queryInterface.sequelize.query(
|
const sequenceCurrentValResult = await queryInterface.sequelize.query(
|
||||||
`select last_value
|
`select last_value
|
||||||
from ${sequenceName}`,
|
from ${sequenceName}`,
|
||||||
{
|
{
|
||||||
transaction,
|
transaction,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const sequenceCurrentVal = parseInt(sequenceCurrentValResult[0][0]['last_value']);
|
const sequenceCurrentVal = parseInt(sequenceCurrentValResult[0][0]['last_value']);
|
||||||
|
|
||||||
if (sequenceCurrentVal > maxSequenceVal) {
|
if (sequenceCurrentVal > maxSequenceVal) {
|
||||||
maxSequenceName = sequenceName;
|
maxSequenceName = sequenceName;
|
||||||
maxSequenceVal = sequenceCurrentVal;
|
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 we have max sequence, set it to child table
|
||||||
if (maxSequenceName) {
|
if (maxSequenceName) {
|
||||||
const parentsDeep = Array.from(db.inheritanceMap.getParents(inheritedCollection.name)).map((parent) =>
|
const parentsDeep = Array.from(db.inheritanceMap.getParents(inheritedCollection.name)).map((parent) =>
|
||||||
db.getCollection(parent).getTableNameWithSchema(),
|
db.getCollection(parent).getTableNameWithSchema(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const sequenceTables = [...parentsDeep, tableName];
|
const sequenceTables = [...parentsDeep, tableName];
|
||||||
|
|
||||||
for (const sequenceTable of sequenceTables) {
|
for (const sequenceTable of sequenceTables) {
|
||||||
const tableName = sequenceTable.tableName;
|
const tableName = sequenceTable.tableName;
|
||||||
const schemaName = sequenceTable.schema;
|
const schemaName = sequenceTable.schema;
|
||||||
|
|
||||||
const idColumnSql = `SELECT column_name
|
const idColumnSql = `SELECT column_name
|
||||||
FROM information_schema.columns
|
FROM information_schema.columns
|
||||||
WHERE table_name = '${tableName}'
|
WHERE table_name = '${tableName}'
|
||||||
and column_name = 'id'
|
and column_name = 'id'
|
||||||
and table_schema = '${schemaName}';
|
and table_schema = '${schemaName}';
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const idColumnQuery = await queryInterface.sequelize.query(idColumnSql, {
|
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,
|
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