Skip to content

Instantly share code, notes, and snippets.

@xpsteven
Last active May 6, 2021 10:28
Show Gist options
  • Save xpsteven/2ccafb94b9455bf101ef56b15cbfd270 to your computer and use it in GitHub Desktop.
Save xpsteven/2ccafb94b9455bf101ef56b15cbfd270 to your computer and use it in GitHub Desktop.
/** 允許的值型別 */
type AVAILABLE_VALUE_TYPE = boolean | number | string | Date;
/** 空物件型別 */
export type EMPTY_OBJECT = Record<string, never>;
/** 任意表頭泛型 */
export type AnyMyRecordBody = Record<string, AVAILABLE_VALUE_TYPE>;
/** 任意表身泛型 */
export interface AnyMyRecordLines {
[lineName: string]: AnyMyRecordBody;
}
/**
* 指定型別的 MyTableRecord
* @template B 表頭形別
* @template L 表身型別 eg `{ lineName1: { lineFieldName1: string; lineFieldName2: number } }`
* @example
* interface VendorLines {
* items: { name: string; qty: number };
* contacts: { name: string; email: string };
* }
* const a: MyTableTypedRecord<{ name: string }, VendorLines> = null;
*/
export interface MyRecord<B = AnyMyRecordBody, L = AnyMyRecordLines> {
/** 編號 */
_id?: number;
/** 表頭 */
body: B;
/** 表身集合 */
lines: {
/** 表身 */
[lineName in keyof L]: Array<L[lineName]>;
};
/** 紀錄表身最大 _id,目前不會傳到前端,值從 -1 開始 */
_lineMaxId?: {
[lineName in keyof L]: number;
};
}
/**
* 任意紀錄
* @note 因為 typescript 無法最雙層索引介面的 extends 推論,所以這邊表身泛型只用一層
*/
export type AnyMyRecord = MyRecord<AnyMyRecordBody, AnyMyRecordLines>;
/** MyModel 內建表頭欄位 */
interface MyModelBodyField {
/** 建立時間 */
_createdAt?: Date;
/** 更新時間 */
_updatedAt?: Date;
/** 封存時間 */
_archivedAt?: Date;
/** 建立者資訊 */
_createdBy?: string;
/** 更新者資訊 */
_updatedBy?: string;
/** 封存者資訊 */
_archivedBy?: string;
}
interface MyModeRecordLineRowField {
/** 表身列索引 */
_id?: number
}
/** MyModel 特化的 MyRecord */
export type MyModelRecord<B = AnyMyRecordBody, L = AnyMyRecordLines> = MyRecord<
B & MyModelBodyField,
{ [lineName in keyof L]: L[lineName] & MyModeRecordLineRowField }
>;
/** MyModel 特化的 MyRecord,允許所有欄位為 null|undefined */
export type MyModelNullishRecord<B = AnyMyRecordBody, L = AnyMyRecordLines> = MyRecord<
Partial<B> & MyModelBodyField,
{ [lineName in keyof L]: Partial<L[lineName]> & MyModeRecordLineRowField }
>;
/** 值類型 */
export enum MyTableValueType {
/** 32 位元整數 */
INT = 'INT',
/** 53 位元整數 */
SAFE_INT = 'SAFE_INT',
/** 浮點數 */
FLOAT = 'FLOAT',
/** 字串 */
STRING = 'STRING',
/** 日期時間 */
DATE = 'DATE',
/** 列舉 */
ENUM = 'ENUM',
/** 布林 */
BOOLEAN = 'BOOLEAN'
}
/** 使用者欄位類型 */
export enum MyTableFieldType {
/**
* 使用者鍵欄位
* @description 限制
* 1. allowNull 必須為 false 或 null
* 1. readWrite 必須為 INSERT
* 1. 只能用在表頭欄位
*/
USER_KEY = 'USER_KEY',
/** 資料欄位 */
DATA = 'DATA',
/** 圖片欄位 */
IMAGE = 'IMAGE',
/** 檔案欄位 */
FILE = 'FILE',
/** 關聯到其他表的 USER_KEY */
REF_USER_KEY = 'REF_USER_KEY',
/**
* 關聯資料欄位
* @description 說明
* 1. 開發者無法使用此類型
* 2. 產生給前端讀取的表格定義才會用到
*/
REF_DATA = 'REF_DATA',
/**
* 關聯圖片欄位
* @description 說明
* 1. 開發者無法使用此類型
* 1. 產生給前端讀取的表格定義才會用到
*/
REF_IMAGE = 'REF_IMAGE'
}
/** 欄位讀寫模式 INSERT / READ / UPDATE */
export enum MyTableFieldReadWrite {
/** 可以新增、不能更新、可以讀取 */
INSERT = 'INSERT',
/** 只能讀取 */
READ = 'READ',
/** 可以新增、可以更新、可以讀取 */
UPDATE = 'UPDATE',
}
/**
* 欄位定義
* @template F 欄位名稱
* @template E 列舉
*/
export interface MyTableField<F, E> {
//#region 欄位基本設定
/** 欄位名稱 */
name: F;
/** 顯示名稱 */
displayName: string;
/** 描述 */
description?: string;
/** 欄位類型 */
fieldType: MyTableFieldType;
/** 資料型別 */
valueType: MyTableValueType;
/** 讀寫模式 */
readWrite: MyTableFieldReadWrite;
/** 列舉名稱 */
enumName?: E;
/** 參考表格名稱,當 fieldType 為 REF_USER_KEY 時為必要 */
refTableName?: string;
/** 參考欄位名稱,當 fieldType 為 REF_USER_KEY 時為必要 */
refFieldName?: string;
/** 參考來源欄位,只有 fieldType=REF_DATA 才會有,只有前端使用到的欄位,不存在於資料庫 */
refSrcFieldName?: string;
//#endregion
//#region 欄位修飾子
/** 是否允許 null,只影響 insert */
allowNull?: boolean;
/** 封存 */
archived?: boolean;
/** 欄位群組 */
groupName?: string;
/** 欄位群組中順序 */
ordering?: number;
//#endregion
//#region 資料驗證
/** 數值最小 */
numberMin?: number;
/** 數值最大 */
numberMax?: number;
/** 日期最小 */
dateMin?: Date;
/** 日期最大 */
dateMax?: Date;
/** 字串正規表示式 */
stringRegExp?: string;
/** 電子郵件格式驗證 */
isEmail?: boolean;
/** 手機號碼格式驗證 */
isMobile?: string;
//#endregion
}
/**
* 表身欄位
* @template L lineName
* @template F fieldName
* @template E enum
*/
export interface MyTableLineField<L, F, E> extends MyTableField<F, E> {
/** 屬於哪一種 line */
lineName: L;
/** 是否作為表身鍵 */
isLineKey?: boolean;
}
/** 任意表頭欄位 */
export type AnyMyTableField = MyTableField<string, string>;
/** 任意表身欄位 */
export type AnyMyTableLineField = MyTableLineField<string, string, string>;
/** 表格類型 */
export enum MyTableType {
/** 表格表格 */
TABLE = 'TABLE',
/** 資料表格 */
DATA = 'DATA',
/** 圖片表格 */
IMAGE = 'IMAGE',
/** 簽核表格 */
FLOW = 'FLOW',
/** 簽核規則 */
FLOW_RULE = 'FLOW_RULE',
/** 簽核群組 */
FLOW_GROUP = 'FLOW_GROUP',
/** 使用者 */
USER = 'USER',
/** 使用者群組 */
GROUP = 'GROUP',
}
/** MyTable 表頭欄位 */
export interface MyTableBody {
/** 表格名稱 */
name: string;
/** 顯示名稱 */
displayName: string;
/** 說明 */
description?: string;
/** 表格類型 default `DATA` */
type: MyTableType;
}
/** 表身讀寫 */
export enum MyTableLineReadWrite {
/** 只能讀取,系統用 */
READ = 'READ',
/** 可以:新增、移除、修改、讀取 */
FULL = 'FULL',
/** 可以:新增、修改、讀取。不可以:移除 */
UPDATE = 'UPDATE',
/** 可以:新增、移除、讀取。不可以:修改 */
PULL = 'PULL',
/** 可以:新增、讀取。不可以:移除、修改 */
PUSH = 'PUSH',
}
/** 可以移除表身列的表身讀寫模式 */
export const PULLABLE_LINE_READ_WRITE = [
MyTableLineReadWrite.FULL,
MyTableLineReadWrite.PULL,
];
/** 可以修改表身列的表身讀寫模式 */
export const UPDATABLE_LINE_READ_WRITE = [
MyTableLineReadWrite.FULL,
MyTableLineReadWrite.UPDATE,
];
/** 可以新增表身列的表身讀寫模式 */
export const PUSHABLE_LINE_READ_WRITE = [
MyTableLineReadWrite.FULL,
MyTableLineReadWrite.PULL,
MyTableLineReadWrite.PUSH,
MyTableLineReadWrite.UPDATE,
];
/**
* 表身
* @template L 表身名稱
*/
export interface MyTableLine<L> {
/** 表身名稱 */
name: L;
/** 顯示名稱 */
displayName: string;
/** 表身讀寫 */
readWrite: MyTableLineReadWrite;
/** 排序 */
ordering?: number;
/** 說明 */
description?: string;
}
/** 任意表身定義 */
export type AnyMyTableLine = MyTableLine<any>;
/**
* 列舉
* @template E 列舉名稱
*/
export interface MyTableEnum<E> {
/** 列舉名稱 */
enum: E;
/** 成員名稱 */
member: string;
/** 成員值 */
displayName: string;
/** 說明 */
description?: string;
}
/** MyTable 的列舉類型 */
export type MYTABLE_ENUMS = 'FieldType' | 'ValueType' | 'ReadWrite' | 'LineReadWrite' | 'TableType';
/** 欄位群組 */
interface MyTableFieldGroup<L> {
/** 哪個表身,null 代表表頭 */
lineName?: L;
/** 群組名稱,只有 20 字限制 */
name: string;
/** 順序 */
ordering: number;
}
/**
* MyTable 表身欄位
* @template BF bodyFieldName
* @template E enumName
* @template L lineName
* @template LF lineFieldName
*/
export interface MyTableLines<BF, L, LF, E> {
/** 表頭欄位 */
bodyFields: MyTableField<BF, E>;
/** 表身欄位 */
lineFields: MyTableLineField<L, LF, E>;
/** 表身 */
lines: MyTableLine<L>;
/** 列舉 */
enums: MyTableEnum<E>;
/** 欄位群組 */
fieldGroups: MyTableFieldGroup<L>;
}
/**
* MyTable 紀錄
* @template BF bodyFieldName
* @template L lineName
* @template LF lineFieldName
* @template E enumName
*/
export type MyTableRecord<BF, L, LF, E> = MyRecord<MyTableBody, MyTableLines<BF, L, LF, E>>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment