fix(database): index invalid (#564)

* fix(database): index invalid

* fix: test error
This commit is contained in:
chenos 2022-07-01 09:33:05 +08:00 committed by GitHub
parent 41cb3da448
commit 70ab4dcf1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 136 additions and 19 deletions

View File

@ -13,6 +13,22 @@ describe('collection', () => {
await db.close();
});
test.skip('indexes', async () => {
await db.clean({ drop: true });
const collection = db.collection({
name: 'test',
fields: [
{
type: 'string',
name: 'name',
index: true,
},
],
});
collection.removeField('name');
await db.sync();
});
test('removeFromDb', async () => {
await db.clean({ drop: true });
const collection = db.collection({

View File

@ -1,6 +1,6 @@
import { Collection } from '../collection';
import { Database } from '../database';
import { updateAssociation, updateAssociations } from '../update-associations';
import { updateAssociations } from '../update-associations';
import { mockDatabase } from './';
describe('update associations', () => {
@ -356,13 +356,14 @@ describe('update associations', () => {
});
describe('belongsToMany', () => {
let db;
let Post;
let Tag;
let PostTag;
let db: Database;
let Post: Collection;
let Tag: Collection;
let PostTag: Collection;
beforeEach(async () => {
db = mockDatabase();
await db.clean({ drop: true });
PostTag = db.collection({
name: 'posts_tags',
fields: [{ type: 'string', name: 'tagged_at' }],
@ -389,7 +390,7 @@ describe('update associations', () => {
afterEach(async () => {
await db.close();
});
test('set through value', async () => {
test.only('set through value', async () => {
const p1 = await Post.repository.create({
values: {
title: 'hello',
@ -404,9 +405,12 @@ describe('update associations', () => {
],
},
});
const t1 = (await p1.getTags())[0];
expect(t1.posts_tags.tagged_at).toEqual('123');
const count = await PostTag.repository.count({
filter: {
tagged_at: '123',
},
});
expect(count).toEqual(1);
});
});
});

View File

@ -1,7 +1,14 @@
import merge from 'deepmerge';
import { EventEmitter } from 'events';
import { default as lodash, default as _ } from 'lodash';
import { ModelCtor, ModelOptions, QueryInterfaceDropTableOptions, SyncOptions, Transactionable } from 'sequelize';
import {
ModelCtor,
ModelOptions,
QueryInterfaceDropTableOptions,
SyncOptions,
Transactionable,
Utils
} from 'sequelize';
import { Database } from './database';
import { Field, FieldOptions } from './fields';
import { Model } from './model';
@ -278,6 +285,67 @@ export class Collection<
this.setField(options.name || name, options);
}
addIndex(index: any) {
if (!index) {
return;
}
let indexes: any = this.model.options.indexes || [];
let indexName = [];
let indexItem;
if (typeof index === 'string') {
indexItem = {
fields: [index],
};
indexName = [index];
} else if (Array.isArray(index)) {
indexItem = {
fields: index,
};
indexName = index;
} else if (index?.fields) {
indexItem = index;
indexName = index.fields;
}
if (lodash.isEqual(this.model.primaryKeyAttributes, indexName)) {
return;
}
const name: string = this.model.primaryKeyAttributes.join(',');
if (name.startsWith(`${indexName.join(',')},`)) {
return;
}
for (const item of indexes) {
if (lodash.isEqual(item.fields, indexName)) {
return;
}
const name: string = item.fields.join(',');
if (name.startsWith(`${indexName.join(',')},`)) {
return;
}
}
if (!indexItem) {
return;
}
indexes.push(indexItem);
this.model.options.indexes = indexes;
const tableName = this.model.getTableName();
// @ts-ignore
this.model._indexes = this.model.options.indexes
// @ts-ignore
.map((index) => Utils.nameIndex(this.model._conformIndex(index), tableName));
}
removeIndex(fields: any) {
if (!fields) {
return;
}
// @ts-ignore
const indexes: any[] = this.model._indexes;
// @ts-ignore
this.model._indexes = indexes.filter((item) => {
return !lodash.isEqual(item.fields, fields);
});
}
async sync(syncOptions?: SyncOptions) {
const modelNames = [this.model.name];

View File

@ -46,7 +46,7 @@ export class BelongsToField extends RelationField {
// @ts-ignore
this.options.sourceKey = association.sourceKey;
}
this.collection.addIndex([this.options.foreignKey]);
return true;
}
@ -68,6 +68,7 @@ export class BelongsToField extends RelationField {
delete collection.model.associations[this.name];
// @ts-ignore
collection.model.refreshAttributes();
// this.collection.removeIndex([this.options.foreignKey]);
}
}

View File

@ -58,6 +58,8 @@ export class BelongsToManyField extends RelationField {
if (!this.options.through) {
this.options.through = this.through;
}
Through.addIndex([this.options.foreignKey]);
Through.addIndex([this.options.otherKey]);
return true;
}

View File

@ -171,11 +171,17 @@ export abstract class Field {
model.rawAttributes[this.name] = this.toSequelize();
// @ts-ignore
model.refreshAttributes();
if (this.options.index) {
this.context.collection.addIndex([this.name]);
}
}
unbind() {
const { model } = this.context.collection;
model.removeAttribute(this.name);
if (this.options.index) {
this.context.collection.removeIndex([this.name]);
}
}
toSequelize(): any {

View File

@ -7,7 +7,7 @@ import {
HasManyOptions as SequelizeHasManyOptions,
Utils
} from 'sequelize';
import { Collection } from '../collection';
import { MultipleRelationFieldOptions, RelationField } from './relation-field';
export interface HasManyFieldOptions extends HasManyOptions {
@ -98,7 +98,6 @@ export class HasManyField extends RelationField {
as: this.name,
foreignKey: this.foreignKey,
});
// inverse relation
// this.TargetModel.belongsTo(collection.model);
@ -112,6 +111,15 @@ export class HasManyField extends RelationField {
// @ts-ignore
this.options.sourceKey = association.sourceKey;
}
let tcoll: Collection;
if (this.target === collection.name) {
tcoll = collection;
} else {
tcoll = database.getCollection(this.target);
}
if (tcoll) {
tcoll.addIndex([this.options.foreignKey]);
}
return true;
}
@ -120,7 +128,7 @@ export class HasManyField extends RelationField {
// 如果关系字段还没建立就删除了,也同步删除待建立关联的关系字段
database.removePendingField(this);
// 如果关系表内没有显式的创建外键字段,删除关系时,外键也删除掉
const tcoll = database.collections.get(this.target);
const tcoll = database.getCollection(this.target);
const foreignKey = this.options.foreignKey;
const field = tcoll.findField((field) => {
if (field.name === foreignKey) {

View File

@ -7,6 +7,7 @@ import {
HasOneOptions as SequelizeHasOneOptions,
Utils
} from 'sequelize';
import { Collection } from '../collection';
import { BaseRelationFieldOptions, RelationField } from './relation-field';
export interface HasOneFieldOptions extends HasOneOptions {
@ -106,6 +107,15 @@ export class HasOneField extends RelationField {
// @ts-ignore
this.options.sourceKey = association.sourceKey;
}
let tcoll: Collection;
if (this.target === collection.name) {
tcoll = collection;
} else {
tcoll = database.getCollection(this.target);
}
if (tcoll) {
tcoll.addIndex([this.options.foreignKey]);
}
return true;
}

View File

@ -17,6 +17,7 @@ export default defineCollection({
{
type: 'string',
name: 'recordId',
index: true,
},
{
type: 'string',

View File

@ -44,6 +44,7 @@ export default {
targetKey: 'name',
foreignKey: 'collectionName',
sortBy: 'sort',
constraints: true,
},
],
} as CollectionOptions;

View File

@ -26,12 +26,14 @@ export default defineCollection({
target: 'uiRoutes',
sourceKey: 'key',
foreignKey: 'parentKey',
constraints: true,
},
{
type: 'belongsTo',
name: 'uiSchema',
target: 'uiSchemas',
foreignKey: 'uiSchemaUid'
foreignKey: 'uiSchemaUid',
constraints: true,
},
{
type: 'json',

View File

@ -63,8 +63,7 @@ export default class UsersPlugin extends Plugin<UserPluginConfig> {
dataIndex: 'state.currentUser.id',
createOnly: true,
visible: true,
onDelete: 'SET NULL',
onUpdate: 'CASCADE',
index: true,
});
collection.setField('createdBy', {
type: 'belongsTo',
@ -79,8 +78,7 @@ export default class UsersPlugin extends Plugin<UserPluginConfig> {
dataType: 'integer',
dataIndex: 'state.currentUser.id',
visible: true,
onDelete: 'SET NULL',
onUpdate: 'CASCADE',
index: true,
});
collection.setField('updatedBy', {
type: 'belongsTo',