nocobase/packages/database-next/src/fields/belongs-to-field.ts
chenos c2ff7882bc
feat: database next (#130)
* FIX: database test with sqlite

* more types

* filter test

* split filter parser

* filter test

* filter test: hasMany

* define inverse association for belongsTo & hasMany

* chore: console.log

* repository count method

* chore: Collection

* repository filter & appends & fields & expect

* repository: sort option

* chore: test

* add: test

* find & findAndCount

* chore: test

* database-next: update guard

* database-next: update guard associationKeysToBeUpdate

* chore: comment

* update-guard OneToOne Association

* has one repository

* support through table value

* belongs to many repository

* has many repository

* has many repository find

* fix: has many find and count

* clean code

* add count method

* chore: multiple relation

* chore: single relation

* repository find

* relation repository builder

* repository count

* repository count test

* fix test

* close db afterEach test

* sort with associations

* repository update

* has many repository: destroy

* belongs to many repository: destroy

* add transaction decorator

* belongs to many with transaction

* has many with transaction

* clean types

* clean types

* clean types

* repository transaction

* fix test

* single relation repository with transaction

* single relation repository with transaction

* fix: test

* fix: option parser fields append

* fix: typo

* fix: string type

* fix: import

* collection field methods

* cleanup

* collection sync

* fix: import

* fix: test

* collection update field

* collection update options

* database hook

* database test

* database event test

* update database event

* add async emmit mixin

* async model event

* database import

* fix: model hook type

* fix: collection event

* recall model.init on collection update

* skip redefine collection test

* skip collection model update

* add model hook class

* global model event support

* chore

* chore

* change utils import

* add field types

* database import

* more import test

* test case

* fix: through model init...

* bugfix

* fix

* update database import

* collection sync by foreachModel

* fix collection model sync

* update

* add field types

* custom operator

* sqlite array field

* postgresql array field

* array query escape

* mysql array operators

* date operators

* array field sqlite fix

* association operator

* date operator empty & notEmpty

* fix: fields import

* fix array field nested association

* filter parse prepare

* fix test

* string field empty

* add date operator test

* field option types

* fix typo

* fix: operator name conflict

* rename function

Co-authored-by: Chareice <chareice@live.com>
2021-12-06 21:12:54 +08:00

82 lines
2.5 KiB
TypeScript

import { omit } from 'lodash';
import { Sequelize, ModelCtor, Model, DataTypes, Utils } from 'sequelize';
import { BaseRelationFieldOptions, RelationField } from './relation-field';
import { HasInverseField } from './has-inverse-field';
import { BaseColumnFieldOptions, Field } from './field';
import { HasManyField } from './has-many-field';
import { BelongsToOptions as SequelizeBelongsToOptions } from 'sequelize/types/lib/associations/belongs-to';
export class BelongsToField extends RelationField {
static type = 'belongsTo';
get target() {
const { target, name } = this.options;
return target || Utils.pluralize(name);
}
bind() {
const { database, collection } = this.context;
const Target = this.TargetModel;
// if target model not exists, add it to pending field,
// it will bind later
if (!Target) {
database.addPendingField(this);
return false;
}
if (collection.model.associations[this.name]) {
delete collection.model.associations[this.name];
}
// define relation on sequelize model
const association = collection.model.belongsTo(Target, {
as: this.name,
...omit(this.options, ['name', 'type', 'target']),
});
// inverse relation
this.TargetModel.hasMany(collection.model);
// 建立关系之后从 pending 列表中删除
database.removePendingField(this);
if (!this.options.foreignKey) {
this.options.foreignKey = association.foreignKey;
}
if (!this.options.sourceKey) {
// @ts-ignore
this.options.sourceKey = association.sourceKey;
}
return true;
}
unbind() {
const { database, collection } = this.context;
// 如果关系字段还没建立就删除了,也同步删除待建立关联的关系字段
database.removePendingField(this);
// 如果外键没有显式的创建,关系表也无反向关联字段,删除关系时,外键也删除掉
const tcoll = database.collections.get(this.target);
const foreignKey = this.options.foreignKey;
const field1 = collection.getField(foreignKey);
const field2 = tcoll.findField((field) => {
return field.type === 'hasMany' && field.foreignKey === foreignKey;
});
if (!field1 && !field2) {
collection.model.removeAttribute(foreignKey);
}
// 删掉 model 的关联字段
delete collection.model.associations[this.name];
// @ts-ignore
collection.model.refreshAttributes();
}
}
export interface BelongsToFieldOptions
extends BaseRelationFieldOptions,
SequelizeBelongsToOptions {
type: 'belongsTo';
}