mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-08 15:09:27 +08:00
* refactor: date field support timezone, defaultToCurrentTime, and onUpdateToCurrentTime * refactor: availableTypes unixTimestamp * chore: defaultToCurrentTime * chore: unix timestamp field * fix: bug * chore: field type map * refactor: local improve * fix: bug * fix: bug * chore: timezone test * chore: test * fix: test * fix: test * chore: field setter * chore: test * chore: date only field * chore: test * chore: test * fix: bug * fix: unixTimestamp * fix: unixTimestamp * chore: accuracy * fix: bug * fix: bug * fix: unixTimestamp * fix: unixTimestamp * fix: date & datetime * refactor: add DateFieldInterface * fix: bug * chore: test * chore: test * chore: test * refactor: locale improve * refactor: local improve * fix: bug * refactor: unixTimestamp not support default value * refactor: timezone * refactor: datetimeNoTzFieldInterface * refactor: locale improve * refactor: locale improve * fix: test * fix: bug * chore: datetime no tz field * refactor: datetimeNoTz * refactor: datetime * fix: bug * refactor: timeFormat * style: collection fields style improve * refactor: defaultToCurrentTime * fix: datetime no tz * chore: field type map * fix: bug * fix: bug * refactor: createAt & updateAt * fix: bug * fix: no tz field with timezone * refactor: dateonly * fix: test * chore: data type map * fix: dateonly * fix: dateonly * fix: datetime * refactor: locale improve * refactor: unixtimestamp * fix: merge bug * fix: bug * fix: datetime * fix: datetime no tz * fix: datetime no tz * chore: mysql datetime map * chore: test * chore: test * chore: test * chore: datetimeTz field * fix: no interface option * refactor: update type * refactor: update type * fix: pg no tz field * chore: save iso8601 format to no tz field * fix: test * fix: test * refactor: gannt & calender startTime & endTime * refactor: unixTimestamp * chore: filter of datetime field * chore: test * chore: test * fix: test * fix: datetime no tz filter * chore: test * chore: test * fix: datetime default value in mysql * fix: sqlite test * chore: test * fix: test * fix: test * fix: $dateOn * fix: bug * fix: bug * refactor: datepicker * fix: test * refactor: datePicker * refactor: gantt setting --------- Co-authored-by: katherinehhh <katherine_15995@163.com>
187 lines
4.4 KiB
TypeScript
187 lines
4.4 KiB
TypeScript
/**
|
|
* This file is part of the NocoBase (R) project.
|
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
* Authors: NocoBase Team.
|
|
*
|
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
*/
|
|
|
|
import _ from 'lodash';
|
|
import { DataType, ModelAttributeColumnOptions, ModelIndexesOptions, SyncOptions, Transactionable } from 'sequelize';
|
|
import { Collection } from '../collection';
|
|
import { Database } from '../database';
|
|
import { ModelEventTypes } from '../types';
|
|
import { snakeCase } from '../utils';
|
|
|
|
export interface FieldContext {
|
|
database: Database;
|
|
collection: Collection;
|
|
}
|
|
|
|
export interface BaseFieldOptions {
|
|
name?: string;
|
|
hidden?: boolean;
|
|
translation?: boolean;
|
|
|
|
[key: string]: any;
|
|
}
|
|
|
|
export interface BaseColumnFieldOptions extends BaseFieldOptions, Omit<ModelAttributeColumnOptions, 'type'> {
|
|
dataType?: DataType;
|
|
index?: boolean | ModelIndexesOptions;
|
|
}
|
|
|
|
export abstract class Field {
|
|
options: any;
|
|
context: FieldContext;
|
|
database: Database;
|
|
collection: Collection;
|
|
|
|
[key: string]: any;
|
|
|
|
constructor(options?: any, context?: FieldContext) {
|
|
this.context = context as any;
|
|
this.database = this.context.database;
|
|
this.collection = this.context.collection;
|
|
this.options = options || {};
|
|
this.init();
|
|
}
|
|
|
|
get name() {
|
|
return this.options.name;
|
|
}
|
|
|
|
get type() {
|
|
return this.options.type;
|
|
}
|
|
|
|
abstract get dataType(): any;
|
|
|
|
isRelationField() {
|
|
return false;
|
|
}
|
|
|
|
async sync(syncOptions: SyncOptions) {
|
|
await this.collection.sync({
|
|
...syncOptions,
|
|
force: false,
|
|
alter: {
|
|
drop: false,
|
|
},
|
|
});
|
|
}
|
|
|
|
init() {
|
|
// code
|
|
}
|
|
|
|
on(eventName: ModelEventTypes, listener: (...args: any[]) => void) {
|
|
this.database.on(`${this.collection.name}.${eventName}`, listener);
|
|
return this;
|
|
}
|
|
|
|
off(eventName: string, listener: (...args: any[]) => void) {
|
|
this.database.off(`${this.collection.name}.${eventName}`, listener);
|
|
return this;
|
|
}
|
|
|
|
get(name: string) {
|
|
return this.options[name];
|
|
}
|
|
|
|
remove() {
|
|
this.collection.removeIndex([this.name]);
|
|
return this.collection.removeField(this.name);
|
|
}
|
|
|
|
columnName() {
|
|
if (this.options.field) {
|
|
return this.options.field;
|
|
}
|
|
|
|
if (this.database.options.underscored) {
|
|
return snakeCase(this.name);
|
|
}
|
|
|
|
return this.name;
|
|
}
|
|
|
|
async existsInDb(options?: Transactionable) {
|
|
const opts = {
|
|
transaction: options?.transaction,
|
|
};
|
|
let sql;
|
|
if (this.database.sequelize.getDialect() === 'sqlite') {
|
|
sql = `SELECT *
|
|
from pragma_table_info('${this.collection.model.tableName}')
|
|
WHERE name = '${this.columnName()}'`;
|
|
} else if (this.database.inDialect('mysql', 'mariadb')) {
|
|
sql = `
|
|
select column_name
|
|
from INFORMATION_SCHEMA.COLUMNS
|
|
where TABLE_SCHEMA = '${this.database.options.database}'
|
|
AND TABLE_NAME = '${this.collection.model.tableName}'
|
|
AND column_name = '${this.columnName()}'
|
|
`;
|
|
} else {
|
|
sql = `
|
|
select column_name
|
|
from INFORMATION_SCHEMA.COLUMNS
|
|
where TABLE_NAME = '${this.collection.model.tableName}'
|
|
AND column_name = '${this.columnName()}'
|
|
AND table_schema = '${this.collection.collectionSchema() || 'public'}'
|
|
`;
|
|
}
|
|
const [rows] = await this.database.sequelize.query(sql, opts);
|
|
return rows.length > 0;
|
|
}
|
|
|
|
merge(obj: any) {
|
|
Object.assign(this.options, obj);
|
|
}
|
|
|
|
bind() {
|
|
const { model } = this.context.collection;
|
|
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;
|
|
|
|
delete model.prototype[this.name];
|
|
|
|
model.removeAttribute(this.name);
|
|
if (this.options.index || this.options.unique) {
|
|
this.context.collection.removeIndex([this.name]);
|
|
}
|
|
}
|
|
|
|
toSequelize(): any {
|
|
const opts = _.omit(this.options, ['name']);
|
|
|
|
if (this.dataType) {
|
|
// @ts-ignore
|
|
Object.assign(opts, { type: this.database.sequelize.normalizeDataType(this.dataType) });
|
|
}
|
|
|
|
Object.assign(opts, this.additionalSequelizeOptions());
|
|
|
|
return opts;
|
|
}
|
|
|
|
additionalSequelizeOptions() {
|
|
return {};
|
|
}
|
|
|
|
typeToString() {
|
|
return this.dataType.toString();
|
|
}
|
|
}
|