ChengLei Shao a7df0e3fd3
refactor: datetime field (#5084)
* 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>
2024-09-10 15:25:20 +08:00

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();
}
}