fix(database): index invalid (#564)
* fix(database): index invalid * fix: test error
This commit is contained in:
parent
41cb3da448
commit
70ab4dcf1f
@ -13,6 +13,22 @@ describe('collection', () => {
|
|||||||
await db.close();
|
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 () => {
|
test('removeFromDb', async () => {
|
||||||
await db.clean({ drop: true });
|
await db.clean({ drop: true });
|
||||||
const collection = db.collection({
|
const collection = db.collection({
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Collection } from '../collection';
|
import { Collection } from '../collection';
|
||||||
import { Database } from '../database';
|
import { Database } from '../database';
|
||||||
import { updateAssociation, updateAssociations } from '../update-associations';
|
import { updateAssociations } from '../update-associations';
|
||||||
import { mockDatabase } from './';
|
import { mockDatabase } from './';
|
||||||
|
|
||||||
describe('update associations', () => {
|
describe('update associations', () => {
|
||||||
@ -356,13 +356,14 @@ describe('update associations', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('belongsToMany', () => {
|
describe('belongsToMany', () => {
|
||||||
let db;
|
let db: Database;
|
||||||
let Post;
|
let Post: Collection;
|
||||||
let Tag;
|
let Tag: Collection;
|
||||||
let PostTag;
|
let PostTag: Collection;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
db = mockDatabase();
|
db = mockDatabase();
|
||||||
|
await db.clean({ drop: true });
|
||||||
PostTag = db.collection({
|
PostTag = db.collection({
|
||||||
name: 'posts_tags',
|
name: 'posts_tags',
|
||||||
fields: [{ type: 'string', name: 'tagged_at' }],
|
fields: [{ type: 'string', name: 'tagged_at' }],
|
||||||
@ -389,7 +390,7 @@ describe('update associations', () => {
|
|||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
await db.close();
|
await db.close();
|
||||||
});
|
});
|
||||||
test('set through value', async () => {
|
test.only('set through value', async () => {
|
||||||
const p1 = await Post.repository.create({
|
const p1 = await Post.repository.create({
|
||||||
values: {
|
values: {
|
||||||
title: 'hello',
|
title: 'hello',
|
||||||
@ -404,9 +405,12 @@ describe('update associations', () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const count = await PostTag.repository.count({
|
||||||
const t1 = (await p1.getTags())[0];
|
filter: {
|
||||||
expect(t1.posts_tags.tagged_at).toEqual('123');
|
tagged_at: '123',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(count).toEqual(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
import merge from 'deepmerge';
|
import merge from 'deepmerge';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { default as lodash, default as _ } from 'lodash';
|
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 { Database } from './database';
|
||||||
import { Field, FieldOptions } from './fields';
|
import { Field, FieldOptions } from './fields';
|
||||||
import { Model } from './model';
|
import { Model } from './model';
|
||||||
@ -278,6 +285,67 @@ export class Collection<
|
|||||||
this.setField(options.name || name, options);
|
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) {
|
async sync(syncOptions?: SyncOptions) {
|
||||||
const modelNames = [this.model.name];
|
const modelNames = [this.model.name];
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ export class BelongsToField extends RelationField {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.options.sourceKey = association.sourceKey;
|
this.options.sourceKey = association.sourceKey;
|
||||||
}
|
}
|
||||||
|
this.collection.addIndex([this.options.foreignKey]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,6 +68,7 @@ export class BelongsToField extends RelationField {
|
|||||||
delete collection.model.associations[this.name];
|
delete collection.model.associations[this.name];
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
collection.model.refreshAttributes();
|
collection.model.refreshAttributes();
|
||||||
|
// this.collection.removeIndex([this.options.foreignKey]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +58,8 @@ export class BelongsToManyField extends RelationField {
|
|||||||
if (!this.options.through) {
|
if (!this.options.through) {
|
||||||
this.options.through = this.through;
|
this.options.through = this.through;
|
||||||
}
|
}
|
||||||
|
Through.addIndex([this.options.foreignKey]);
|
||||||
|
Through.addIndex([this.options.otherKey]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,11 +171,17 @@ export abstract class Field {
|
|||||||
model.rawAttributes[this.name] = this.toSequelize();
|
model.rawAttributes[this.name] = this.toSequelize();
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
model.refreshAttributes();
|
model.refreshAttributes();
|
||||||
|
if (this.options.index) {
|
||||||
|
this.context.collection.addIndex([this.name]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unbind() {
|
unbind() {
|
||||||
const { model } = this.context.collection;
|
const { model } = this.context.collection;
|
||||||
model.removeAttribute(this.name);
|
model.removeAttribute(this.name);
|
||||||
|
if (this.options.index) {
|
||||||
|
this.context.collection.removeIndex([this.name]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toSequelize(): any {
|
toSequelize(): any {
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
HasManyOptions as SequelizeHasManyOptions,
|
HasManyOptions as SequelizeHasManyOptions,
|
||||||
Utils
|
Utils
|
||||||
} from 'sequelize';
|
} from 'sequelize';
|
||||||
|
import { Collection } from '../collection';
|
||||||
import { MultipleRelationFieldOptions, RelationField } from './relation-field';
|
import { MultipleRelationFieldOptions, RelationField } from './relation-field';
|
||||||
|
|
||||||
export interface HasManyFieldOptions extends HasManyOptions {
|
export interface HasManyFieldOptions extends HasManyOptions {
|
||||||
@ -98,7 +98,6 @@ export class HasManyField extends RelationField {
|
|||||||
as: this.name,
|
as: this.name,
|
||||||
foreignKey: this.foreignKey,
|
foreignKey: this.foreignKey,
|
||||||
});
|
});
|
||||||
|
|
||||||
// inverse relation
|
// inverse relation
|
||||||
// this.TargetModel.belongsTo(collection.model);
|
// this.TargetModel.belongsTo(collection.model);
|
||||||
|
|
||||||
@ -112,6 +111,15 @@ export class HasManyField extends RelationField {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.options.sourceKey = association.sourceKey;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +128,7 @@ export class HasManyField extends RelationField {
|
|||||||
// 如果关系字段还没建立就删除了,也同步删除待建立关联的关系字段
|
// 如果关系字段还没建立就删除了,也同步删除待建立关联的关系字段
|
||||||
database.removePendingField(this);
|
database.removePendingField(this);
|
||||||
// 如果关系表内没有显式的创建外键字段,删除关系时,外键也删除掉
|
// 如果关系表内没有显式的创建外键字段,删除关系时,外键也删除掉
|
||||||
const tcoll = database.collections.get(this.target);
|
const tcoll = database.getCollection(this.target);
|
||||||
const foreignKey = this.options.foreignKey;
|
const foreignKey = this.options.foreignKey;
|
||||||
const field = tcoll.findField((field) => {
|
const field = tcoll.findField((field) => {
|
||||||
if (field.name === foreignKey) {
|
if (field.name === foreignKey) {
|
||||||
|
@ -7,6 +7,7 @@ import {
|
|||||||
HasOneOptions as SequelizeHasOneOptions,
|
HasOneOptions as SequelizeHasOneOptions,
|
||||||
Utils
|
Utils
|
||||||
} from 'sequelize';
|
} from 'sequelize';
|
||||||
|
import { Collection } from '../collection';
|
||||||
import { BaseRelationFieldOptions, RelationField } from './relation-field';
|
import { BaseRelationFieldOptions, RelationField } from './relation-field';
|
||||||
|
|
||||||
export interface HasOneFieldOptions extends HasOneOptions {
|
export interface HasOneFieldOptions extends HasOneOptions {
|
||||||
@ -106,6 +107,15 @@ export class HasOneField extends RelationField {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.options.sourceKey = association.sourceKey;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ export default defineCollection({
|
|||||||
{
|
{
|
||||||
type: 'string',
|
type: 'string',
|
||||||
name: 'recordId',
|
name: 'recordId',
|
||||||
|
index: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
@ -44,6 +44,7 @@ export default {
|
|||||||
targetKey: 'name',
|
targetKey: 'name',
|
||||||
foreignKey: 'collectionName',
|
foreignKey: 'collectionName',
|
||||||
sortBy: 'sort',
|
sortBy: 'sort',
|
||||||
|
constraints: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
} as CollectionOptions;
|
} as CollectionOptions;
|
||||||
|
@ -26,12 +26,14 @@ export default defineCollection({
|
|||||||
target: 'uiRoutes',
|
target: 'uiRoutes',
|
||||||
sourceKey: 'key',
|
sourceKey: 'key',
|
||||||
foreignKey: 'parentKey',
|
foreignKey: 'parentKey',
|
||||||
|
constraints: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'belongsTo',
|
type: 'belongsTo',
|
||||||
name: 'uiSchema',
|
name: 'uiSchema',
|
||||||
target: 'uiSchemas',
|
target: 'uiSchemas',
|
||||||
foreignKey: 'uiSchemaUid'
|
foreignKey: 'uiSchemaUid',
|
||||||
|
constraints: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'json',
|
type: 'json',
|
||||||
|
@ -63,8 +63,7 @@ export default class UsersPlugin extends Plugin<UserPluginConfig> {
|
|||||||
dataIndex: 'state.currentUser.id',
|
dataIndex: 'state.currentUser.id',
|
||||||
createOnly: true,
|
createOnly: true,
|
||||||
visible: true,
|
visible: true,
|
||||||
onDelete: 'SET NULL',
|
index: true,
|
||||||
onUpdate: 'CASCADE',
|
|
||||||
});
|
});
|
||||||
collection.setField('createdBy', {
|
collection.setField('createdBy', {
|
||||||
type: 'belongsTo',
|
type: 'belongsTo',
|
||||||
@ -79,8 +78,7 @@ export default class UsersPlugin extends Plugin<UserPluginConfig> {
|
|||||||
dataType: 'integer',
|
dataType: 'integer',
|
||||||
dataIndex: 'state.currentUser.id',
|
dataIndex: 'state.currentUser.id',
|
||||||
visible: true,
|
visible: true,
|
||||||
onDelete: 'SET NULL',
|
index: true,
|
||||||
onUpdate: 'CASCADE',
|
|
||||||
});
|
});
|
||||||
collection.setField('updatedBy', {
|
collection.setField('updatedBy', {
|
||||||
type: 'belongsTo',
|
type: 'belongsTo',
|
||||||
|
Loading…
Reference in New Issue
Block a user