Merge branch 'release'

This commit is contained in:
Xu Chang 2023-01-31 20:57:59 +08:00
commit 9dad16432c
48 changed files with 922 additions and 477 deletions

View File

@ -1,16 +1,16 @@
import { ActionDef } from '../types/Action';
export type ReadOnlyAction = 'select' | 'count' | 'stat' | 'download';
export type AppendOnlyAction = ReadOnlyAction | 'create';
export type ExcludeUpdateAction = AppendOnlyAction | 'remove';
export type ExcludeRemoveAction = AppendOnlyAction | 'update';
export type GenericAction = 'update' | ExcludeUpdateAction;
export type RelationAction = 'grant' | 'revoke';
export declare type ReadOnlyAction = 'select' | 'count' | 'stat' | 'download' | 'aggregate';
export declare type AppendOnlyAction = ReadOnlyAction | 'create';
export declare type ExcludeUpdateAction = AppendOnlyAction | 'remove';
export declare type ExcludeRemoveAction = AppendOnlyAction | 'update';
export declare type GenericAction = 'update' | ExcludeUpdateAction;
export declare type RelationAction = 'grant' | 'revoke';
export declare const readOnlyActions: string[];
export declare const appendOnlyActions: string[];
export declare const excludeUpdateActions: string[];
export declare const exludeRemoveActions: string[];
export declare const genericActions: string[];
export declare const relationActions: string[];
export type AbleAction = 'enable' | 'disable';
export type AbleState = 'enabled' | 'disabled';
export declare type AbleAction = 'enable' | 'disable';
export declare type AbleState = 'enabled' | 'disabled';
export declare const makeAbleActionDef: (initialState?: AbleState) => ActionDef<AbleAction, AbleState>;

View File

@ -1,7 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeAbleActionDef = exports.relationActions = exports.genericActions = exports.exludeRemoveActions = exports.excludeUpdateActions = exports.appendOnlyActions = exports.readOnlyActions = void 0;
exports.readOnlyActions = ['count', 'stat', 'download', 'select'];
exports.readOnlyActions = ['count', 'stat', 'download', 'select', 'aggregate'];
exports.appendOnlyActions = exports.readOnlyActions.concat('create');
exports.excludeUpdateActions = exports.appendOnlyActions.concat('remove');
exports.exludeRemoveActions = exports.appendOnlyActions.concat('update');

View File

@ -1,5 +1,5 @@
import { CascadeRelationItem, RelationHierarchy } from "../types/Entity";
export type GenericRelation = 'owner';
export declare type GenericRelation = 'owner';
export declare function convertHierarchyToAuth<R extends string>(hierarchy: RelationHierarchy<R>): {
[K in R]?: CascadeRelationItem;
};

View File

@ -3,7 +3,7 @@ import { EntityDef as ModiEntity } from "./ModiEntity/Schema";
import { EntityDef as Oper } from "./Oper/Schema";
import { EntityDef as OperEntity } from "./OperEntity/Schema";
import { EntityDef as User } from "./User/Schema";
export type EntityDict = {
export declare type EntityDict = {
modi: Modi;
modiEntity: ModiEntity;
oper: Oper;

View File

@ -1,9 +1,9 @@
import { ActionDef } from "../../types/Action";
import { GenericAction } from "../../actions/action";
export type IState = 'active' | 'applied' | 'abandoned';
export type IAction = 'apply' | 'abandon';
export type ParticularAction = IAction;
export type Action = GenericAction | ParticularAction;
export declare type IState = 'active' | 'applied' | 'abandoned';
export declare type IAction = 'apply' | 'abandon';
export declare type ParticularAction = IAction;
export declare type Action = GenericAction | ParticularAction;
export declare const actions: string[];
export declare const ActionDefDict: {
iState: ActionDef<IAction, IState>;

View File

@ -8,7 +8,7 @@ var IActionDef = {
},
is: 'active'
};
exports.actions = ["count", "stat", "download", "select", "create", "remove", "update", "apply", "abandon"];
exports.actions = ["count", "stat", "download", "select", "aggregate", "create", "remove", "update", "apply", "abandon"];
exports.ActionDefDict = {
iState: IActionDef
};

View File

@ -2,11 +2,11 @@ import { String } from "../../types/DataType";
import { Q_DateValue, Q_StringValue, Q_EnumValue, NodeId, MakeFilter, ExprOp, ExpressionKey } from "../../types/Demand";
import { OneOf } from "../../types/Polyfill";
import * as SubQuery from "../_SubQuery";
import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOperation, MakeAction as OakMakeAction, EntityShape, AggregationResult } from "../../types/Entity";
import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOperation, Selection as OakSelection, MakeAction as OakMakeAction, EntityShape, AggregationResult } from "../../types/Entity";
import { Action, ParticularAction, IState } from "./Action";
import * as ModiEntity from "../ModiEntity/Schema";
import * as OperEntity from "../OperEntity/Schema";
export type OpSchema = EntityShape & {
export declare type OpSchema = EntityShape & {
targetEntity: String<32>;
entity: String<32>;
entityId: String<64>;
@ -16,8 +16,8 @@ export type OpSchema = EntityShape & {
extra?: Object | null;
iState?: IState | null;
};
export type OpAttr = keyof OpSchema;
export type Schema = EntityShape & {
export declare type OpAttr = keyof OpSchema;
export declare type Schema = EntityShape & {
targetEntity: String<32>;
entity: String<32>;
entityId: String<64>;
@ -33,7 +33,7 @@ export type Schema = EntityShape & {
} & {
[A in ExpressionKey]?: any;
};
type AttrFilter = {
declare type AttrFilter = {
id: Q_StringValue | SubQuery.ModiIdSubQuery;
$$createAt$$: Q_DateValue;
$$seq$$: Q_StringValue;
@ -47,8 +47,8 @@ type AttrFilter = {
extra: Object;
iState: Q_EnumValue<IState>;
};
export type Filter = MakeFilter<AttrFilter & ExprOp<OpAttr | string>>;
export type Projection = {
export declare type Filter = MakeFilter<AttrFilter & ExprOp<OpAttr | string>>;
export declare type Projection = {
"#id"?: NodeId;
[k: string]: any;
id?: number;
@ -76,10 +76,10 @@ export type Projection = {
$entity: "operEntity";
};
} & Partial<ExprOp<OpAttr | string>>;
type ModiIdProjection = OneOf<{
declare type ModiIdProjection = OneOf<{
id: number;
}>;
export type SortAttr = {
export declare type SortAttr = {
id: number;
} | {
$$createAt$$: number;
@ -100,15 +100,15 @@ export type SortAttr = {
} | {
[k: string]: any;
} | OneOf<ExprOp<OpAttr | string>>;
export type SortNode = {
export declare type SortNode = {
$attr: SortAttr;
$direction?: "asc" | "desc";
};
export type Sorter = SortNode[];
export type SelectOperation<P extends Object = Projection> = Omit<OakOperation<"select", P, Filter, Sorter>, "id">;
export type Selection<P extends Object = Projection> = Omit<SelectOperation<P>, "action">;
export type Aggregation = Omit<DeduceAggregation<Projection, Filter, Sorter>, "id">;
export type CreateOperationData = FormCreateData<Omit<OpSchema, "entity" | "entityId">> & ({
export declare type Sorter = SortNode[];
export declare type SelectOperation<P extends Object = Projection> = OakSelection<"select", P, Filter, Sorter>;
export declare type Selection<P extends Object = Projection> = Omit<SelectOperation<P>, "action">;
export declare type Aggregation = DeduceAggregation<Projection, Filter, Sorter>;
export declare type CreateOperationData = FormCreateData<Omit<OpSchema, "entity" | "entityId">> & ({
entity?: string;
entityId?: string;
[K: string]: any;
@ -116,20 +116,20 @@ export type CreateOperationData = FormCreateData<Omit<OpSchema, "entity" | "enti
modiEntity$modi?: OakOperation<"create", Omit<ModiEntity.CreateOperationData, "modi" | "modiId">[]> | Array<OakOperation<"create", Omit<ModiEntity.CreateOperationData, "modi" | "modiId">>>;
operEntity$entity?: OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">>>;
};
export type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
export type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
export type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
export type UpdateOperationData = FormUpdateData<OpSchema> & {
export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
export declare type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
export declare type UpdateOperationData = FormUpdateData<OpSchema> & {
[k: string]: any;
modiEntitys$modi?: OakOperation<"create", Omit<ModiEntity.CreateOperationData, "modi" | "modiId">[]> | Array<OakOperation<"create", Omit<ModiEntity.CreateOperationData, "modi" | "modiId">>>;
operEntitys$entity?: OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">>>;
modiEntity$modi?: OakOperation<"create", Omit<ModiEntity.CreateOperationData, "modi" | "modiId">[]> | Array<OakOperation<"create", Omit<ModiEntity.CreateOperationData, "modi" | "modiId">>>;
operEntity$entity?: OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">>>;
};
export type UpdateOperation = OakOperation<"update" | ParticularAction | string, UpdateOperationData, Filter, Sorter>;
export type RemoveOperationData = {};
export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
export type Operation = CreateOperation | UpdateOperation | RemoveOperation;
export type ModiIdSubQuery = Selection<ModiIdProjection>;
export type EntityDef = {
export declare type UpdateOperation = OakOperation<"update" | ParticularAction | string, UpdateOperationData, Filter, Sorter>;
export declare type RemoveOperationData = {};
export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation;
export declare type ModiIdSubQuery = Selection<ModiIdProjection>;
export declare type EntityDef = {
Schema: Schema;
OpSchema: OpSchema;
Action: OakMakeAction<Action> | string;

View File

@ -2,17 +2,17 @@ import { String, ForeignKey } from "../../types/DataType";
import { Q_DateValue, Q_StringValue, Q_EnumValue, NodeId, MakeFilter, ExprOp, ExpressionKey } from "../../types/Demand";
import { OneOf } from "../../types/Polyfill";
import * as SubQuery from "../_SubQuery";
import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOperation, MakeAction as OakMakeAction, EntityShape } from "../../types/Entity";
import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOperation, Selection as OakSelection, MakeAction as OakMakeAction, EntityShape } from "../../types/Entity";
import { AppendOnlyAction } from "../../actions/action";
import * as Modi from "../Modi/Schema";
import * as User from "../User/Schema";
export type OpSchema = EntityShape & {
export declare type OpSchema = EntityShape & {
modiId: ForeignKey<"modi">;
entity: "user" | string;
entityId: String<64>;
};
export type OpAttr = keyof OpSchema;
export type Schema = EntityShape & {
export declare type OpAttr = keyof OpSchema;
export declare type Schema = EntityShape & {
modiId: ForeignKey<"modi">;
entity: "user" | string;
entityId: String<64>;
@ -21,7 +21,7 @@ export type Schema = EntityShape & {
} & {
[A in ExpressionKey]?: any;
};
type AttrFilter<E> = {
declare type AttrFilter<E> = {
id: Q_StringValue | SubQuery.ModiEntityIdSubQuery;
$$createAt$$: Q_DateValue;
$$seq$$: Q_StringValue;
@ -32,8 +32,8 @@ type AttrFilter<E> = {
entityId: Q_StringValue;
user: User.Filter;
};
export type Filter<E = Q_EnumValue<"user" | string>> = MakeFilter<AttrFilter<E> & ExprOp<OpAttr | string>>;
export type Projection = {
export declare type Filter<E = Q_EnumValue<"user" | string>> = MakeFilter<AttrFilter<E> & ExprOp<OpAttr | string>>;
export declare type Projection = {
"#id"?: NodeId;
[k: string]: any;
id?: number;
@ -46,16 +46,16 @@ export type Projection = {
entityId?: number;
user?: User.Projection;
} & Partial<ExprOp<OpAttr | string>>;
type ModiEntityIdProjection = OneOf<{
declare type ModiEntityIdProjection = OneOf<{
id: number;
}>;
type ModiIdProjection = OneOf<{
declare type ModiIdProjection = OneOf<{
modiId: number;
}>;
type UserIdProjection = OneOf<{
declare type UserIdProjection = OneOf<{
entityId: number;
}>;
export type SortAttr = {
export declare type SortAttr = {
id: number;
} | {
$$createAt$$: number;
@ -76,15 +76,15 @@ export type SortAttr = {
} | {
[k: string]: any;
} | OneOf<ExprOp<OpAttr | string>>;
export type SortNode = {
export declare type SortNode = {
$attr: SortAttr;
$direction?: "asc" | "desc";
};
export type Sorter = SortNode[];
export type SelectOperation<P extends Object = Projection> = Omit<OakOperation<"select", P, Filter, Sorter>, "id">;
export type Selection<P extends Object = Projection> = Omit<SelectOperation<P>, "action">;
export type Aggregation = Omit<DeduceAggregation<Projection, Filter, Sorter>, "id">;
export type CreateOperationData = FormCreateData<Omit<OpSchema, "entity" | "entityId" | "modiId">> & (({
export declare type Sorter = SortNode[];
export declare type SelectOperation<P extends Object = Projection> = OakSelection<"select", P, Filter, Sorter>;
export declare type Selection<P extends Object = Projection> = Omit<SelectOperation<P>, "action">;
export declare type Aggregation = DeduceAggregation<Projection, Filter, Sorter>;
export declare type CreateOperationData = FormCreateData<Omit<OpSchema, "entity" | "entityId" | "modiId">> & (({
modiId?: never;
modi: Modi.CreateSingleOperation;
} | {
@ -108,10 +108,10 @@ export type CreateOperationData = FormCreateData<Omit<OpSchema, "entity" | "enti
entityId?: string;
[K: string]: any;
});
export type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
export type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
export type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "entity" | "entityId" | "modiId">> & (({
export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
export declare type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
export declare type UpdateOperationData = FormUpdateData<Omit<OpSchema, "entity" | "entityId" | "modiId">> & (({
modi: Modi.CreateSingleOperation;
modiId?: never;
} | {
@ -133,20 +133,20 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "entity" | "enti
}) & {
[k: string]: any;
};
export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
export type RemoveOperationData = {} & (({
export declare type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
export declare type RemoveOperationData = {} & (({
modi?: Modi.UpdateOperation | Modi.RemoveOperation;
})) & ({
user?: User.UpdateOperation | User.RemoveOperation;
} | {
[k: string]: any;
});
export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
export type Operation = CreateOperation | UpdateOperation | RemoveOperation;
export type ModiIdSubQuery = Selection<ModiIdProjection>;
export type UserIdSubQuery = Selection<UserIdProjection>;
export type ModiEntityIdSubQuery = Selection<ModiEntityIdProjection>;
export type EntityDef = {
export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation;
export declare type ModiIdSubQuery = Selection<ModiIdProjection>;
export declare type UserIdSubQuery = Selection<UserIdProjection>;
export declare type ModiEntityIdSubQuery = Selection<ModiEntityIdProjection>;
export declare type EntityDef = {
Schema: Schema;
OpSchema: OpSchema;
Action: OakMakeAction<AppendOnlyAction> | string;

View File

@ -2,19 +2,19 @@ import { String, ForeignKey } from "../../types/DataType";
import { Q_DateValue, Q_StringValue, NodeId, MakeFilter, ExprOp, ExpressionKey } from "../../types/Demand";
import { OneOf } from "../../types/Polyfill";
import * as SubQuery from "../_SubQuery";
import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOperation, MakeAction as OakMakeAction, EntityShape, AggregationResult } from "../../types/Entity";
import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOperation, Selection as OakSelection, MakeAction as OakMakeAction, EntityShape, AggregationResult } from "../../types/Entity";
import { AppendOnlyAction } from "../../actions/action";
import * as User from "../User/Schema";
import * as OperEntity from "../OperEntity/Schema";
export type OpSchema = EntityShape & {
export declare type OpSchema = EntityShape & {
action: String<16>;
data: Object;
filter?: Object | null;
extra?: Object | null;
operatorId?: ForeignKey<"user"> | null;
};
export type OpAttr = keyof OpSchema;
export type Schema = EntityShape & {
export declare type OpAttr = keyof OpSchema;
export declare type Schema = EntityShape & {
action: String<16>;
data: Object;
filter?: Object | null;
@ -26,7 +26,7 @@ export type Schema = EntityShape & {
} & {
[A in ExpressionKey]?: any;
};
type AttrFilter = {
declare type AttrFilter = {
id: Q_StringValue | SubQuery.OperIdSubQuery;
$$createAt$$: Q_DateValue;
$$seq$$: Q_StringValue;
@ -38,8 +38,8 @@ type AttrFilter = {
operatorId: Q_StringValue | SubQuery.UserIdSubQuery;
operator: User.Filter;
};
export type Filter = MakeFilter<AttrFilter & ExprOp<OpAttr | string>>;
export type Projection = {
export declare type Filter = MakeFilter<AttrFilter & ExprOp<OpAttr | string>>;
export declare type Projection = {
"#id"?: NodeId;
[k: string]: any;
id?: number;
@ -59,13 +59,13 @@ export type Projection = {
$entity: "operEntity";
};
} & Partial<ExprOp<OpAttr | string>>;
type OperIdProjection = OneOf<{
declare type OperIdProjection = OneOf<{
id: number;
}>;
type UserIdProjection = OneOf<{
declare type UserIdProjection = OneOf<{
operatorId: number;
}>;
export type SortAttr = {
export declare type SortAttr = {
id: number;
} | {
$$createAt$$: number;
@ -82,15 +82,15 @@ export type SortAttr = {
} | {
[k: string]: any;
} | OneOf<ExprOp<OpAttr | string>>;
export type SortNode = {
export declare type SortNode = {
$attr: SortAttr;
$direction?: "asc" | "desc";
};
export type Sorter = SortNode[];
export type SelectOperation<P extends Object = Projection> = Omit<OakOperation<"select", P, Filter, Sorter>, "id">;
export type Selection<P extends Object = Projection> = Omit<SelectOperation<P>, "action">;
export type Aggregation = Omit<DeduceAggregation<Projection, Filter, Sorter>, "id">;
export type CreateOperationData = FormCreateData<Omit<OpSchema, "operatorId">> & (({
export declare type Sorter = SortNode[];
export declare type SelectOperation<P extends Object = Projection> = OakSelection<"select", P, Filter, Sorter>;
export declare type Selection<P extends Object = Projection> = Omit<SelectOperation<P>, "action">;
export declare type Aggregation = DeduceAggregation<Projection, Filter, Sorter>;
export declare type CreateOperationData = FormCreateData<Omit<OpSchema, "operatorId">> & (({
operatorId?: never;
operator?: User.CreateSingleOperation;
} | {
@ -101,10 +101,10 @@ export type CreateOperationData = FormCreateData<Omit<OpSchema, "operatorId">> &
})) & {
operEntity$oper?: OakOperation<"create", Omit<OperEntity.CreateOperationData, "oper" | "operId">[]> | Array<OakOperation<"create", Omit<OperEntity.CreateOperationData, "oper" | "operId">>>;
};
export type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
export type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
export type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "operatorId">> & (({
export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
export declare type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
export declare type UpdateOperationData = FormUpdateData<Omit<OpSchema, "operatorId">> & (({
operator: User.CreateSingleOperation;
operatorId?: never;
} | {
@ -118,17 +118,17 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "operatorId">> &
operatorId?: String<64> | null;
})) & {
[k: string]: any;
operEntitys$oper?: OakOperation<"create", Omit<OperEntity.CreateOperationData, "oper" | "operId">[]> | Array<OakOperation<"create", Omit<OperEntity.CreateOperationData, "oper" | "operId">>>;
operEntity$oper?: OakOperation<"create", Omit<OperEntity.CreateOperationData, "oper" | "operId">[]> | Array<OakOperation<"create", Omit<OperEntity.CreateOperationData, "oper" | "operId">>>;
};
export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
export type RemoveOperationData = {} & (({
export declare type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
export declare type RemoveOperationData = {} & (({
operator?: User.UpdateOperation | User.RemoveOperation;
}));
export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
export type Operation = CreateOperation | UpdateOperation | RemoveOperation;
export type UserIdSubQuery = Selection<UserIdProjection>;
export type OperIdSubQuery = Selection<OperIdProjection>;
export type EntityDef = {
export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation;
export declare type UserIdSubQuery = Selection<UserIdProjection>;
export declare type OperIdSubQuery = Selection<OperIdProjection>;
export declare type EntityDef = {
Schema: Schema;
OpSchema: OpSchema;
Action: OakMakeAction<AppendOnlyAction> | string;

View File

@ -2,18 +2,18 @@ import { String, ForeignKey } from "../../types/DataType";
import { Q_DateValue, Q_StringValue, Q_EnumValue, NodeId, MakeFilter, ExprOp, ExpressionKey } from "../../types/Demand";
import { OneOf } from "../../types/Polyfill";
import * as SubQuery from "../_SubQuery";
import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOperation, MakeAction as OakMakeAction, EntityShape } from "../../types/Entity";
import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOperation, Selection as OakSelection, MakeAction as OakMakeAction, EntityShape } from "../../types/Entity";
import { AppendOnlyAction } from "../../actions/action";
import * as Oper from "../Oper/Schema";
import * as Modi from "../Modi/Schema";
import * as User from "../User/Schema";
export type OpSchema = EntityShape & {
export declare type OpSchema = EntityShape & {
operId: ForeignKey<"oper">;
entity: "modi" | "user" | string;
entityId: String<64>;
};
export type OpAttr = keyof OpSchema;
export type Schema = EntityShape & {
export declare type OpAttr = keyof OpSchema;
export declare type Schema = EntityShape & {
operId: ForeignKey<"oper">;
entity: "modi" | "user" | string;
entityId: String<64>;
@ -23,7 +23,7 @@ export type Schema = EntityShape & {
} & {
[A in ExpressionKey]?: any;
};
type AttrFilter<E> = {
declare type AttrFilter<E> = {
id: Q_StringValue | SubQuery.OperEntityIdSubQuery;
$$createAt$$: Q_DateValue;
$$seq$$: Q_StringValue;
@ -35,8 +35,8 @@ type AttrFilter<E> = {
modi: Modi.Filter;
user: User.Filter;
};
export type Filter<E = Q_EnumValue<"modi" | "user" | string>> = MakeFilter<AttrFilter<E> & ExprOp<OpAttr | string>>;
export type Projection = {
export declare type Filter<E = Q_EnumValue<"modi" | "user" | string>> = MakeFilter<AttrFilter<E> & ExprOp<OpAttr | string>>;
export declare type Projection = {
"#id"?: NodeId;
[k: string]: any;
id?: number;
@ -50,19 +50,19 @@ export type Projection = {
modi?: Modi.Projection;
user?: User.Projection;
} & Partial<ExprOp<OpAttr | string>>;
type OperEntityIdProjection = OneOf<{
declare type OperEntityIdProjection = OneOf<{
id: number;
}>;
type OperIdProjection = OneOf<{
declare type OperIdProjection = OneOf<{
operId: number;
}>;
type ModiIdProjection = OneOf<{
declare type ModiIdProjection = OneOf<{
entityId: number;
}>;
type UserIdProjection = OneOf<{
declare type UserIdProjection = OneOf<{
entityId: number;
}>;
export type SortAttr = {
export declare type SortAttr = {
id: number;
} | {
$$createAt$$: number;
@ -85,15 +85,15 @@ export type SortAttr = {
} | {
[k: string]: any;
} | OneOf<ExprOp<OpAttr | string>>;
export type SortNode = {
export declare type SortNode = {
$attr: SortAttr;
$direction?: "asc" | "desc";
};
export type Sorter = SortNode[];
export type SelectOperation<P extends Object = Projection> = Omit<OakOperation<"select", P, Filter, Sorter>, "id">;
export type Selection<P extends Object = Projection> = Omit<SelectOperation<P>, "action">;
export type Aggregation = Omit<DeduceAggregation<Projection, Filter, Sorter>, "id">;
export type CreateOperationData = FormCreateData<Omit<OpSchema, "entity" | "entityId" | "operId">> & (({
export declare type Sorter = SortNode[];
export declare type SelectOperation<P extends Object = Projection> = OakSelection<"select", P, Filter, Sorter>;
export declare type Selection<P extends Object = Projection> = Omit<SelectOperation<P>, "action">;
export declare type Aggregation = DeduceAggregation<Projection, Filter, Sorter>;
export declare type CreateOperationData = FormCreateData<Omit<OpSchema, "entity" | "entityId" | "operId">> & (({
operId?: never;
oper: Oper.CreateSingleOperation;
} | {
@ -125,10 +125,10 @@ export type CreateOperationData = FormCreateData<Omit<OpSchema, "entity" | "enti
entityId?: string;
[K: string]: any;
});
export type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
export type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
export type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "entity" | "entityId" | "operId">> & (({
export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
export declare type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
export declare type UpdateOperationData = FormUpdateData<Omit<OpSchema, "entity" | "entityId" | "operId">> & (({
oper: Oper.CreateSingleOperation;
operId?: never;
} | {
@ -148,21 +148,21 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "entity" | "enti
}) & {
[k: string]: any;
};
export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
export type RemoveOperationData = {} & ({
export declare type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
export declare type RemoveOperationData = {} & ({
modi?: Modi.UpdateOperation | Modi.RemoveOperation;
} | {
user?: User.UpdateOperation | User.RemoveOperation;
} | {
[k: string]: any;
});
export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
export type Operation = CreateOperation | UpdateOperation | RemoveOperation;
export type OperIdSubQuery = Selection<OperIdProjection>;
export type ModiIdSubQuery = Selection<ModiIdProjection>;
export type UserIdSubQuery = Selection<UserIdProjection>;
export type OperEntityIdSubQuery = Selection<OperEntityIdProjection>;
export type EntityDef = {
export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation;
export declare type OperIdSubQuery = Selection<OperIdProjection>;
export declare type ModiIdSubQuery = Selection<ModiIdProjection>;
export declare type UserIdSubQuery = Selection<UserIdProjection>;
export declare type OperEntityIdSubQuery = Selection<OperEntityIdProjection>;
export declare type EntityDef = {
Schema: Schema;
OpSchema: OpSchema;
Action: OakMakeAction<AppendOnlyAction> | string;

View File

@ -2,18 +2,18 @@ import { String, Text } from "../../types/DataType";
import { Q_DateValue, Q_StringValue, NodeId, MakeFilter, ExprOp, ExpressionKey } from "../../types/Demand";
import { OneOf } from "../../types/Polyfill";
import * as SubQuery from "../_SubQuery";
import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOperation, MakeAction as OakMakeAction, EntityShape, AggregationResult } from "../../types/Entity";
import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOperation, Selection as OakSelection, MakeAction as OakMakeAction, EntityShape, AggregationResult } from "../../types/Entity";
import { GenericAction, RelationAction } from "../../actions/action";
import * as Oper from "../Oper/Schema";
import * as OperEntity from "../OperEntity/Schema";
import * as ModiEntity from "../ModiEntity/Schema";
export type OpSchema = EntityShape & {
export declare type OpSchema = EntityShape & {
name?: String<16> | null;
nickname?: String<64> | null;
password?: Text | null;
};
export type OpAttr = keyof OpSchema;
export type Schema = EntityShape & {
export declare type OpAttr = keyof OpSchema;
export declare type Schema = EntityShape & {
name?: String<16> | null;
nickname?: String<64> | null;
password?: Text | null;
@ -26,7 +26,7 @@ export type Schema = EntityShape & {
} & {
[A in ExpressionKey]?: any;
};
type AttrFilter = {
declare type AttrFilter = {
id: Q_StringValue | SubQuery.UserIdSubQuery;
$$createAt$$: Q_DateValue;
$$seq$$: Q_StringValue;
@ -35,8 +35,8 @@ type AttrFilter = {
nickname: Q_StringValue;
password: Q_StringValue;
};
export type Filter = MakeFilter<AttrFilter & ExprOp<OpAttr | string>>;
export type Projection = {
export declare type Filter = MakeFilter<AttrFilter & ExprOp<OpAttr | string>>;
export declare type Projection = {
"#id"?: NodeId;
[k: string]: any;
id?: number;
@ -65,10 +65,10 @@ export type Projection = {
$entity: "modiEntity";
};
} & Partial<ExprOp<OpAttr | string>>;
type UserIdProjection = OneOf<{
declare type UserIdProjection = OneOf<{
id: number;
}>;
export type SortAttr = {
export declare type SortAttr = {
id: number;
} | {
$$createAt$$: number;
@ -85,34 +85,34 @@ export type SortAttr = {
} | {
[k: string]: any;
} | OneOf<ExprOp<OpAttr | string>>;
export type SortNode = {
export declare type SortNode = {
$attr: SortAttr;
$direction?: "asc" | "desc";
};
export type Sorter = SortNode[];
export type SelectOperation<P extends Object = Projection> = Omit<OakOperation<"select", P, Filter, Sorter>, "id">;
export type Selection<P extends Object = Projection> = Omit<SelectOperation<P>, "action">;
export type Aggregation = Omit<DeduceAggregation<Projection, Filter, Sorter>, "id">;
export type CreateOperationData = FormCreateData<OpSchema> & {
export declare type Sorter = SortNode[];
export declare type SelectOperation<P extends Object = Projection> = OakSelection<"select", P, Filter, Sorter>;
export declare type Selection<P extends Object = Projection> = Omit<SelectOperation<P>, "action">;
export declare type Aggregation = DeduceAggregation<Projection, Filter, Sorter>;
export declare type CreateOperationData = FormCreateData<OpSchema> & {
oper$operator?: OakOperation<"create", Omit<Oper.CreateOperationData, "operator" | "operatorId">[]> | Array<OakOperation<"create", Omit<Oper.CreateOperationData, "operator" | "operatorId">>>;
operEntity$entity?: OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">>>;
modiEntity$entity?: OakOperation<"create", Omit<ModiEntity.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<ModiEntity.CreateOperationData, "entity" | "entityId">>>;
};
export type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
export type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
export type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
export type UpdateOperationData = FormUpdateData<OpSchema> & {
export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
export declare type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
export declare type UpdateOperationData = FormUpdateData<OpSchema> & {
[k: string]: any;
opers$operator?: OakOperation<"create", Omit<Oper.CreateOperationData, "operator" | "operatorId">[]> | Array<OakOperation<"create", Omit<Oper.CreateOperationData, "operator" | "operatorId">>>;
operEntitys$entity?: OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">>>;
modiEntitys$entity?: OakOperation<"create", Omit<ModiEntity.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<ModiEntity.CreateOperationData, "entity" | "entityId">>>;
oper$operator?: OakOperation<"create", Omit<Oper.CreateOperationData, "operator" | "operatorId">[]> | Array<OakOperation<"create", Omit<Oper.CreateOperationData, "operator" | "operatorId">>>;
operEntity$entity?: OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">>>;
modiEntity$entity?: OakOperation<"create", Omit<ModiEntity.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<ModiEntity.CreateOperationData, "entity" | "entityId">>>;
};
export type UpdateOperation = OakOperation<"update" | RelationAction | string, UpdateOperationData, Filter, Sorter>;
export type RemoveOperationData = {};
export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
export type Operation = CreateOperation | UpdateOperation | RemoveOperation;
export type UserIdSubQuery = Selection<UserIdProjection>;
export type EntityDef = {
export declare type UpdateOperation = OakOperation<"update" | RelationAction | string, UpdateOperationData, Filter, Sorter>;
export declare type RemoveOperationData = {};
export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation;
export declare type UserIdSubQuery = Selection<UserIdProjection>;
export declare type EntityDef = {
Schema: Schema;
OpSchema: OpSchema;
Action: OakMakeAction<GenericAction | RelationAction> | string;

View File

@ -3,31 +3,31 @@ import * as ModiEntity from "./ModiEntity/Schema";
import * as Oper from "./Oper/Schema";
import * as OperEntity from "./OperEntity/Schema";
import * as User from "./User/Schema";
export type ModiIdSubQuery = {
export declare type ModiIdSubQuery = {
[K in "$in" | "$nin"]?: (ModiEntity.ModiIdSubQuery & {
entity: "modiEntity";
}) | (Modi.ModiIdSubQuery & {
entity: "modi";
}) | any;
};
export type ModiEntityIdSubQuery = {
export declare type ModiEntityIdSubQuery = {
[K in "$in" | "$nin"]?: (ModiEntity.ModiEntityIdSubQuery & {
entity: "modiEntity";
}) | any;
};
export type OperIdSubQuery = {
export declare type OperIdSubQuery = {
[K in "$in" | "$nin"]?: (OperEntity.OperIdSubQuery & {
entity: "operEntity";
}) | (Oper.OperIdSubQuery & {
entity: "oper";
}) | any;
};
export type OperEntityIdSubQuery = {
export declare type OperEntityIdSubQuery = {
[K in "$in" | "$nin"]?: (OperEntity.OperEntityIdSubQuery & {
entity: "operEntity";
}) | any;
};
export type UserIdSubQuery = {
export declare type UserIdSubQuery = {
[K in "$in" | "$nin"]?: (Oper.UserIdSubQuery & {
entity: "oper";
}) | (User.UserIdSubQuery & {

View File

@ -652,12 +652,12 @@ function analyzeEntity(filename, path, program, relativePath) {
return ele2.name.getText() === 'name';
});
(0, assert_1.default)(ts.isStringLiteral(nameProperty.initializer));
var indexName = nameProperty.initializer.text;
if (indexNameDict_1[indexName]) {
throw new Error("\u300C".concat(filename, "\u300D\u7D22\u5F15\u5B9A\u4E49\u91CD\u540D\u300C").concat(indexName, "\u300D"));
var nameText = nameProperty.initializer.text;
if (indexNameDict_1[nameText]) {
throw new Error("\u300C".concat(filename, "\u300D\u7D22\u5F15\u5B9A\u4E49\u91CD\u540D\u300C").concat(nameText, "\u300D"));
}
(0, lodash_1.assign)(indexNameDict_1, (_a = {},
_a[indexName] = true,
_a[nameText] = true,
_a));
var configProperty = properties.find(function (ele2) {
(0, assert_1.default)(ts.isPropertyAssignment(ele2));
@ -695,10 +695,10 @@ function analyzeEntity(filename, path, program, relativePath) {
return ele3.name.text === indexAttrName;
});
if (!schemaNode) {
throw new Error("\u300C".concat(filename, "\u300D\u4E2D\u7D22\u5F15\u300C").concat(indexName, "\u300D\u7684\u5C5E\u6027\u300C").concat(indexAttrName, "\u300D\u5B9A\u4E49\u975E\u6CD5"));
throw new Error("\u300C".concat(filename, "\u300D\u4E2D\u7D22\u5F15\u300C").concat(nameText, "\u300D\u7684\u5C5E\u6027\u300C").concat(indexAttrName, "\u300D\u5B9A\u4E49\u975E\u6CD5"));
}
var type = schemaNode.type, name_1 = schemaNode.name;
var entity = (0, string_1.firstLetterLowerCase)(moduleName);
var entity = moduleName;
var _a = ManyToOne, _b = entity, manyToOneSet = _a[_b];
if (ts.isTypeReferenceNode(type)) {
var typeName = type.typeName;
@ -712,14 +712,19 @@ function analyzeEntity(filename, path, program, relativePath) {
if (!manyToOneItem) {
// 如果不是外键则不能是Text, File
if (isFulltextIndex) {
(0, assert_1.default)(['Text', 'String'].includes(text2_1), "\u300C".concat(filename, "\u300D\u4E2D\u5168\u6587\u7D22\u5F15\u300C").concat(indexName, "\u300D\u5B9A\u4E49\u7684\u5C5E\u6027\u300C").concat(indexAttrName, "\u300D\u7C7B\u578B\u975E\u6CD5\uFF0C\u53EA\u80FD\u662FText/String"));
(0, assert_1.default)(['Text', 'String'].includes(text2_1), "\u300C".concat(filename, "\u300D\u4E2D\u5168\u6587\u7D22\u5F15\u300C").concat(nameText, "\u300D\u5B9A\u4E49\u7684\u5C5E\u6027\u300C").concat(indexAttrName, "\u300D\u7C7B\u578B\u975E\u6CD5\uFF0C\u53EA\u80FD\u662FText/String"));
}
else {
(0, assert_1.default)(!DataType_1.unIndexedTypes.includes(text2_1), "\u300C".concat(filename, "\u300D\u4E2D\u7D22\u5F15\u300C").concat(indexName, "\u300D\u7684\u5C5E\u6027\u300C").concat(indexAttrName, "\u300D\u7684\u7C7B\u578B\u4E3A\u300C").concat(text2_1, "\u300D\uFF0C\u4E0D\u53EF\u7D22\u5F15"));
(0, assert_1.default)(!DataType_1.unIndexedTypes.includes(text2_1), "\u300C".concat(filename, "\u300D\u4E2D\u7D22\u5F15\u300C").concat(nameText, "\u300D\u7684\u5C5E\u6027\u300C").concat(indexAttrName, "\u300D\u7684\u7C7B\u578B\u4E3A\u300C").concat(text2_1, "\u300D\uFF0C\u4E0D\u53EF\u7D22\u5F15"));
}
}
else {
(0, assert_1.default)(!isFulltextIndex, "\u300C".concat(filename, "\u300D\u4E2D\u5168\u6587\u7D22\u5F15\u300C").concat(indexName, "\u300D\u7684\u5C5E\u6027\u300C").concat(indexAttrName, "\u300D\u7C7B\u578B\u975E\u6CD5\uFF0C\u53EA\u80FD\u4E3AText/String"));
(0, assert_1.default)(!isFulltextIndex, "\u300C".concat(filename, "\u300D\u4E2D\u5168\u6587\u7D22\u5F15\u300C").concat(nameText, "\u300D\u7684\u5C5E\u6027\u300C").concat(indexAttrName, "\u300D\u7C7B\u578B\u975E\u6CD5\uFF0C\u53EA\u80FD\u4E3AText/String"));
// 在这里把外键加上Id这样storageSchema才能正常通过
// 这里的写法不太好未来TS版本高了可能会有问题。by Xc 20230131
Object.assign(nameProperty, {
initializer: factory.createStringLiteral("".concat(indexAttrName, "Id")),
});
}
}
else {
@ -727,8 +732,8 @@ function analyzeEntity(filename, path, program, relativePath) {
}
}
else {
(0, assert_1.default)(!isFulltextIndex, "\u300C".concat(filename, "\u300D\u4E2D\u5168\u6587\u7D22\u5F15\u300C").concat(indexName, "\u300D\u7684\u5C5E\u6027\u300C").concat(indexAttrName, "\u300D\u7C7B\u578B\u53EA\u80FD\u4E3AText/String"));
(0, assert_1.default)(ts.isUnionTypeNode(type) || ts.isLiteralTypeNode(type), "".concat(entity, "\u4E2D\u7D22\u5F15\u300C").concat(indexName, "\u300D\u7684\u5C5E\u6027").concat(name_1.text, "\u6709\u5B9A\u4E49\u975E\u6CD5"));
(0, assert_1.default)(!isFulltextIndex, "\u300C".concat(filename, "\u300D\u4E2D\u5168\u6587\u7D22\u5F15\u300C").concat(nameText, "\u300D\u7684\u5C5E\u6027\u300C").concat(indexAttrName, "\u300D\u7C7B\u578B\u53EA\u80FD\u4E3AText/String"));
(0, assert_1.default)(ts.isUnionTypeNode(type) || ts.isLiteralTypeNode(type), "".concat(entity, "\u4E2D\u7D22\u5F15\u300C").concat(nameText, "\u300D\u7684\u5C5E\u6027").concat(name_1.text, "\u6709\u5B9A\u4E49\u975E\u6CD5"));
}
}
});
@ -1077,6 +1082,7 @@ function constructFilter(statements, entity) {
break;
}
case 'Int':
case 'Uint':
case 'Float':
case 'Double': {
type2 = factory.createTypeReferenceNode(factory.createIdentifier('Q_NumberValue'));
@ -1784,14 +1790,11 @@ function constructActions(statements, entity) {
// Selection
statements.push(factory.createTypeAliasDeclaration(undefined, [factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("SelectOperation"), [
factory.createTypeParameterDeclaration(undefined, factory.createIdentifier("P"), factory.createTypeReferenceNode(factory.createIdentifier("Object"), undefined), factory.createTypeReferenceNode(factory.createIdentifier("Projection"), undefined))
], factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
factory.createTypeReferenceNode(factory.createIdentifier("OakOperation"), [
factory.createLiteralTypeNode(factory.createStringLiteral("select")),
factory.createTypeReferenceNode(factory.createIdentifier("P"), undefined),
factory.createTypeReferenceNode(factory.createIdentifier("Filter"), undefined),
factory.createTypeReferenceNode(factory.createIdentifier("Sorter"), undefined)
]),
factory.createLiteralTypeNode(factory.createStringLiteral("id"))
], factory.createTypeReferenceNode(factory.createIdentifier("OakSelection"), [
factory.createLiteralTypeNode(factory.createStringLiteral("select")),
factory.createTypeReferenceNode(factory.createIdentifier("P"), undefined),
factory.createTypeReferenceNode(factory.createIdentifier("Filter"), undefined),
factory.createTypeReferenceNode(factory.createIdentifier("Sorter"), undefined)
])), factory.createTypeAliasDeclaration(undefined, [factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("Selection"), [
factory.createTypeParameterDeclaration(undefined, factory.createIdentifier("P"), factory.createTypeReferenceNode(factory.createIdentifier("Object"), undefined), factory.createTypeReferenceNode(factory.createIdentifier("Projection"), undefined))
], factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
@ -1799,13 +1802,10 @@ function constructActions(statements, entity) {
factory.createTypeReferenceNode(factory.createIdentifier("P"), undefined)
]),
factory.createLiteralTypeNode(factory.createStringLiteral("action"))
])), factory.createTypeAliasDeclaration(undefined, [factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("Aggregation"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
factory.createTypeReferenceNode(factory.createIdentifier("DeduceAggregation"), [
factory.createTypeReferenceNode(factory.createIdentifier("Projection"), undefined),
factory.createTypeReferenceNode(factory.createIdentifier("Filter"), undefined),
factory.createTypeReferenceNode(factory.createIdentifier("Sorter"), undefined)
]),
factory.createLiteralTypeNode(factory.createStringLiteral("id"))
])), factory.createTypeAliasDeclaration(undefined, [factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("Aggregation"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("DeduceAggregation"), [
factory.createTypeReferenceNode(factory.createIdentifier("Projection"), undefined),
factory.createTypeReferenceNode(factory.createIdentifier("Filter"), undefined),
factory.createTypeReferenceNode(factory.createIdentifier("Sorter"), undefined)
])));
// Exportation
// 已经废弃by Xc 2023.01.08
@ -2297,7 +2297,7 @@ function constructActions(statements, entity) {
var _loop_9 = function (entityName) {
var entityNameLc = (0, string_1.firstLetterLowerCase)(entityName);
foreignKeySet[entityName].forEach(function (foreignKey) {
var identifier = "".concat(entityNameLc, "s$").concat(foreignKey);
var identifier = "".concat(entityNameLc, "$").concat(foreignKey);
var otmCreateOperationDataNode = factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
factory.createTypeReferenceNode(createForeignRef(entity, entityName, 'CreateOperationData'), undefined),
factory.createUnionTypeNode(foreignKey === 'entity' ? [
@ -2612,6 +2612,7 @@ var initialStatements = function () { return [
factory.createImportDeclaration(undefined, undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier('String')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Int')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Uint')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Float')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Double')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Boolean')),
@ -2653,6 +2654,7 @@ var initialStatements = function () { return [
factory.createImportSpecifier(false, undefined, factory.createIdentifier("FormUpdateData")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("DeduceAggregation")),
factory.createImportSpecifier(false, factory.createIdentifier("Operation"), factory.createIdentifier("OakOperation")),
factory.createImportSpecifier(false, factory.createIdentifier("Selection"), factory.createIdentifier("OakSelection")),
factory.createImportSpecifier(false, factory.createIdentifier("MakeAction"), factory.createIdentifier("OakMakeAction")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("EntityShape")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("AggregationResult")),

View File

@ -529,7 +529,7 @@ var CascadeStore = /** @class */ (function (_super) {
var _g = tslib_1.__read(relation, 2), entityOtm_1 = _g[0], foreignKey_2 = _g[1];
var otmOperations = data[attr];
var dealWithOneToMany = function (otm) {
var _a, _b, _c, _d;
var _a, _b, _c, _d, _e;
var actionOtm = otm.action, dataOtm = otm.data, filterOtm = otm.filter;
if (!foreignKey_2) {
// 基于entity/entityId的one-to-many
@ -550,7 +550,7 @@ var CascadeStore = /** @class */ (function (_super) {
}
else if (actionOtm === 'create') {
// 这里先假设A必是update的filter上一定有id否则用户界面上应该设计不出来这样的操作
// todo 这个假设成立吗?等遇到create/create一对多的case再完善
// todo 这个假设对watcher等后台行为可能不成立等遇到create/create一对多的case再完善
var id_2 = filter.id;
(0, assert_1.default)(typeof id_2 === 'string');
if (dataOtm instanceof Array) {
@ -569,12 +569,10 @@ var CascadeStore = /** @class */ (function (_super) {
else {
// 这里先假设A必是update的filter上一定有id否则用户界面上应该设计不出来这样的操作
// 这个倒是好像不可能出现create/update的一对多如果遇到了再完善
var id = filter.id;
Object.assign(otm, {
filter: (0, filter_1.addFilterSegment)({
entity: entity,
entityId: id,
}, filterOtm),
filter: (0, filter_1.addFilterSegment)((_a = {},
_a[entity] = filter,
_a), filterOtm),
});
if (action === 'remove' && actionOtm === 'update') {
Object.assign(dataOtm, {
@ -597,14 +595,14 @@ var CascadeStore = /** @class */ (function (_super) {
});
}
else {
Object.assign(dataOtm, (_a = {},
_a[foreignKey_2] = id_3,
_a));
Object.assign(dataOtm, (_b = {},
_b[foreignKey_2] = id_3,
_b));
}
}
else if (actionOtm === 'create') {
// 这里先假设A必是update的filter上一定有id否则用户界面上应该设计不出来这样的操作
// todo 这个假设成立吗等遇到create/create一对多的case再完善
// todo 这个假设在后台可能不成立,等遇到了再说
var id_4 = filter.id;
(0, assert_1.default)(typeof id_4 === 'string');
if (dataOtm instanceof Array) {
@ -616,28 +614,26 @@ var CascadeStore = /** @class */ (function (_super) {
});
}
else {
Object.assign(dataOtm, (_b = {},
_b[foreignKey_2] = id_4,
_b));
Object.assign(dataOtm, (_c = {},
_c[foreignKey_2] = id_4,
_c));
}
}
else {
// 这里先假设A必是update的filter上一定有id否则用户界面上应该设计不出来这样的操作
// 这个倒是好像不可能出现create/update的一对多如果遇到了再完善
var id = filter.id;
// update可能出现上层filter不是根据id的userEntityGrant的过期触发的wechatQrCode的过期见general中的userEntityGrant的trigger
Object.assign(otm, {
filter: (0, filter_1.addFilterSegment)((_c = {},
_c[foreignKey_2] = id,
_c), filterOtm),
filter: (0, filter_1.addFilterSegment)((_d = {},
_d[foreignKey_2.slice(0, foreignKey_2.length - 2)] = filter,
_d), filterOtm),
});
if (action === 'remove' && actionOtm === 'update') {
Object.assign(dataOtm, (_d = {},
_d[foreignKey_2] = null,
_d));
Object.assign(dataOtm, (_e = {},
_e[foreignKey_2] = null,
_e));
}
}
}
afterFns.push(function () { return cascadeUpdate.call(_this, entityOtm_1, otm, context, option2); });
beforeFns.push(function () { return cascadeUpdate.call(_this, entityOtm_1, otm, context, option2); });
};
if (otmOperations instanceof Array) {
try {

View File

@ -16,7 +16,7 @@ export declare class TriggerExecutor<ED extends EntityDict & BaseEntityDict> {
private contextBuilder;
constructor(contextBuilder: (cxtString: string) => Promise<AsyncContext<ED>>, logger?: Logger);
registerChecker<T extends keyof ED, Cxt extends AsyncContext<ED>>(checker: Checker<ED, T, Cxt>): void;
getCheckers<T extends keyof ED>(entity: T, action: ED[T]['Action'], checkerTypes?: CheckerType[]): Trigger<ED, T, AsyncContext<ED>>[];
getCheckers<T extends keyof ED>(entity: T, action: ED[T]['Action'], checkerTypes?: CheckerType[]): Trigger<ED, T, AsyncContext<ED>>[] | undefined;
registerTrigger<T extends keyof ED, Cxt extends AsyncContext<ED>>(trigger: Trigger<ED, T, Cxt>): void;
unregisterTrigger<T extends keyof ED, Cxt extends AsyncContext<ED>>(trigger: Trigger<ED, T, Cxt>): void;
private preCommitTrigger;

View File

@ -2,6 +2,9 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.analyzeActionDefDict = exports.getFullProjection = void 0;
var tslib_1 = require("tslib");
var types_1 = require("../types");
var lodash_1 = require("../utils/lodash");
var filter_1 = require("./filter");
function getFullProjection(entity, schema) {
var attributes = schema[entity].attributes;
var projection = {
@ -20,56 +23,116 @@ function getFullProjection(entity, schema) {
}
exports.getFullProjection = getFullProjection;
function makeIntrinsicWatchers(schema) {
var _this = this;
var watchers = [];
var _loop_1 = function (entity) {
for (var entity in schema) {
var attributes = schema[entity].attributes;
var now = Date.now();
var expiresAt = attributes.expiresAt, expired = attributes.expired;
if (expiresAt && expiresAt.type === 'datetime' && expired && expired.type === 'boolean') {
// 如果有定义expiresAt和expired则自动生成一个检查的watcher
watchers.push({
entity: entity,
name: "\u5BF9\u8C61".concat(entity, "\u4E0A\u7684\u8FC7\u671F\u81EA\u52A8watcher"),
filter: function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
return [2 /*return*/, {
expired: false,
expiresAt: {
$lte: now,
},
}];
});
}); },
filter: function () {
return {
expired: false,
expiresAt: {
$lte: Date.now(),
},
};
},
action: 'update',
actionData: {
expired: true,
},
});
}
};
for (var entity in schema) {
_loop_1(entity);
}
return watchers;
}
function checkUniqueBetweenRows(rows, uniqAttrs) {
// 先检查这些行本身之间有无unique冲突
var uniqRows = (0, lodash_1.uniqBy)(rows, function (d) {
var e_1, _a;
var s = '';
try {
for (var uniqAttrs_1 = tslib_1.__values(uniqAttrs), uniqAttrs_1_1 = uniqAttrs_1.next(); !uniqAttrs_1_1.done; uniqAttrs_1_1 = uniqAttrs_1.next()) {
var a = uniqAttrs_1_1.value;
if (d[a] === null || d[a] === undefined) {
s + d.id;
}
else {
s + "-".concat(d[a]);
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (uniqAttrs_1_1 && !uniqAttrs_1_1.done && (_a = uniqAttrs_1.return)) _a.call(uniqAttrs_1);
}
finally { if (e_1) throw e_1.error; }
}
return s;
});
if (uniqRows.length < rows.length) {
throw new types_1.OakUniqueViolationException([{
attrs: uniqAttrs,
}]);
}
}
function checkCountLessThan(count, uniqAttrs, than, id) {
if (than === void 0) { than = 0; }
if (count instanceof Promise) {
return count.then(function (count2) {
if (count2 > than) {
throw new types_1.OakUniqueViolationException([{
id: id,
attrs: uniqAttrs,
}]);
}
});
}
if (count > than) {
throw new types_1.OakUniqueViolationException([{
id: id,
attrs: uniqAttrs,
}]);
}
}
function checkUnique(entity, row, context, uniqAttrs, extraFilter) {
var filter = (0, lodash_1.pick)(row, uniqAttrs);
for (var a in filter) {
if (filter[a] === null || filter[a] === undefined) {
delete filter[a];
}
}
if (Object.keys(filter).length < uniqAttrs.length) {
// 说明有null值不需要检查约束
return;
}
var filter2 = extraFilter ? (0, filter_1.addFilterSegment)([filter, extraFilter]) : filter;
var count = context.count(entity, { filter: filter2 }, { dontCollect: true });
return checkCountLessThan(count, uniqAttrs, 0, row.id);
}
function analyzeActionDefDict(schema, actionDefDict) {
var _a;
var checkers = [];
var triggers = [];
// action状态转换矩阵相应的checker
for (var entity in actionDefDict) {
var _loop_2 = function (attr) {
var _loop_1 = function (attr) {
var def = actionDefDict[entity][attr];
var _a = def, stm = _a.stm, is = _a.is;
var _b = def, stm = _b.stm, is = _b.is;
var _loop_3 = function (action) {
var _b, _c;
var _c, _d;
var actionStm = stm[action];
var conditionalFilter = typeof actionStm[0] === 'string' ? (_b = {},
_b[attr] = actionStm[0],
_b) : (_c = {},
_c[attr] = {
var conditionalFilter = typeof actionStm[0] === 'string' ? (_c = {},
_c[attr] = actionStm[0],
_c) : (_d = {},
_d[attr] = {
$in: actionStm[0],
},
_c);
_d);
checkers.push({
action: action,
type: 'row',
@ -123,9 +186,144 @@ function analyzeActionDefDict(schema, actionDefDict) {
}
};
for (var attr in actionDefDict[entity]) {
_loop_2(attr);
_loop_1(attr);
}
}
var _loop_2 = function (entity) {
var e_2, _e;
var indexes = schema[entity].indexes;
if (indexes) {
var _loop_4 = function (index) {
if ((_a = index.config) === null || _a === void 0 ? void 0 : _a.unique) {
var attributes = index.attributes;
var uniqAttrs_2 = attributes.map(function (ele) { return ele.name; });
checkers.push({
entity: entity,
action: 'create',
type: 'logical',
priority: 20,
checker: function (operation, context) {
var data = operation.data;
if (data instanceof Array) {
checkUniqueBetweenRows(data, uniqAttrs_2);
var checkResult = data.map(function (ele) { return checkUnique(entity, ele, context, uniqAttrs_2); });
if (checkResult[0] instanceof Promise) {
return Promise.all(checkResult).then(function () { return undefined; });
}
}
else {
return checkUnique(entity, data, context, uniqAttrs_2);
}
}
}, {
entity: entity,
action: 'update',
type: 'logical',
priority: 20,
checker: function (operation, context) {
var e_3, _a, e_4, _b, _c;
var _d = operation, data = _d.data, operationFilter = _d.filter;
var attrs = Object.keys(data);
var refAttrs = (0, lodash_1.intersection)(attrs, uniqAttrs_2);
if (refAttrs.length === 0) {
// 如果本次更新和unique约束的属性之间没有交集则直接返回
return;
}
try {
for (var refAttrs_1 = (e_3 = void 0, tslib_1.__values(refAttrs)), refAttrs_1_1 = refAttrs_1.next(); !refAttrs_1_1.done; refAttrs_1_1 = refAttrs_1.next()) {
var attr = refAttrs_1_1.value;
// 如果有更新为null值不用再检查约束
if (data[attr] === null || data[attr] === undefined) {
return;
}
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (refAttrs_1_1 && !refAttrs_1_1.done && (_a = refAttrs_1.return)) _a.call(refAttrs_1);
}
finally { if (e_3) throw e_3.error; }
}
if (refAttrs.length === uniqAttrs_2.length) {
// 如果更新了全部属性,直接检查
var filter = (0, lodash_1.pick)(data, refAttrs);
// 在这些行以外的行不和更新后的键值冲突
var count = context.count(entity, {
filter: (0, filter_1.addFilterSegment)([filter, {
$not: operationFilter,
}]),
}, { dontCollect: true });
var checkCount = checkCountLessThan(count, uniqAttrs_2);
// 更新的行只能有一行
var rowCount = context.count(entity, {
filter: operationFilter,
}, { dontCollect: true });
var checkRowCount = checkCountLessThan(rowCount, uniqAttrs_2, 1);
// 如果更新的行数为零似乎也可以但这应该不可能出现吧by Xc 20230131
if (checkRowCount instanceof Promise) {
return Promise.all([checkCount, checkRowCount]).then(function () { return undefined; });
}
}
// 否则需要结合本行现有的属性来进行检查
var projection = { id: 1 };
try {
for (var uniqAttrs_3 = (e_4 = void 0, tslib_1.__values(uniqAttrs_2)), uniqAttrs_3_1 = uniqAttrs_3.next(); !uniqAttrs_3_1.done; uniqAttrs_3_1 = uniqAttrs_3.next()) {
var attr = uniqAttrs_3_1.value;
Object.assign(projection, (_c = {},
_c[attr] = 1,
_c));
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (uniqAttrs_3_1 && !uniqAttrs_3_1.done && (_b = uniqAttrs_3.return)) _b.call(uniqAttrs_3);
}
finally { if (e_4) throw e_4.error; }
}
var checkWithRows = function (rows2) {
var rows22 = rows2.map(function (ele) { return Object.assign(ele, data); });
// 先检查这些行本身之间是否冲突
checkUniqueBetweenRows(rows22, uniqAttrs_2);
var checkResults = rows22.map(function (row) { return checkUnique(entity, row, context, uniqAttrs_2, {
$not: operationFilter
}); });
if (checkResults[0] instanceof Promise) {
return Promise.all(checkResults).then(function () { return undefined; });
}
};
var currentRows = context.select(entity, {
data: projection,
filter: operationFilter,
}, { dontCollect: true });
if (currentRows instanceof Promise) {
return currentRows.then(function (row2) { return checkWithRows(row2); });
}
return checkWithRows(currentRows);
}
});
}
};
try {
for (var indexes_1 = (e_2 = void 0, tslib_1.__values(indexes)), indexes_1_1 = indexes_1.next(); !indexes_1_1.done; indexes_1_1 = indexes_1.next()) {
var index = indexes_1_1.value;
_loop_4(index);
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (indexes_1_1 && !indexes_1_1.done && (_e = indexes_1.return)) _e.call(indexes_1);
}
finally { if (e_2) throw e_2.error; }
}
}
};
// unique索引相应的checker
for (var entity in schema) {
_loop_2(entity);
}
return {
triggers: triggers,
checkers: checkers,

10
lib/types/Action.d.ts vendored
View File

@ -1,18 +1,18 @@
import { CascadeRelationItem, EntityDict } from "./Entity";
import { GenericAction } from '../actions/action';
export type Action = string;
export type State = string;
export type ActionDef<A extends Action, S extends State> = {
export declare type Action = string;
export declare type State = string;
export declare type ActionDef<A extends Action, S extends State> = {
stm: {
[a in A]: [p: S | S[], n: S];
};
is?: S;
};
export type ActionDictOfEntityDict<E extends EntityDict> = {
export declare type ActionDictOfEntityDict<E extends EntityDict> = {
[T in keyof E]?: {
[A in keyof E[T]['OpSchema']]?: ActionDef<string, string>;
};
};
export type CascadeActionAuth<A extends Action = ''> = {
export declare type CascadeActionAuth<A extends Action = ''> = {
[K in A | GenericAction]?: CascadeRelationItem | (CascadeRelationItem | CascadeRelationItem[])[];
};

18
lib/types/Auth.d.ts vendored
View File

@ -2,12 +2,12 @@ import { CascadeActionAuth, CascadeRelationAuth } from ".";
import { AsyncContext } from "../store/AsyncRowStore";
import { SyncContext } from "../store/SyncRowStore";
import { EntityDict, OperateOption, SelectOption } from "../types/Entity";
export type CheckerType = 'relation' | 'row' | 'data' | 'logical' | 'logicalRelation';
export declare type CheckerType = 'relation' | 'row' | 'data' | 'logical' | 'logicalRelation';
/**
* conditionalFilter是指该action发生时operation所操作的行中有满足conditionalFilter的行
* trigger的filter条件trigger中的说明
*/
export type DataChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
export declare type DataChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
priority?: number;
type: 'data';
entity: T;
@ -15,7 +15,7 @@ export type DataChecker<ED extends EntityDict, T extends keyof ED, Cxt extends A
checker: (data: ED[T]['Create']['data'] | ED[T]['Update']['data'], context: Cxt) => void | Promise<void>;
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter'] | Promise<ED[T]['Selection']['filter']>);
};
export type RowChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
export declare type RowChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
priority?: number;
type: 'row';
entity: T;
@ -28,7 +28,7 @@ export type RowChecker<ED extends EntityDict, T extends keyof ED, Cxt extends As
};
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter'] | Promise<ED[T]['Update']['filter']>);
};
export type RelationChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
export declare type RelationChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
priority?: number;
type: 'relation';
entity: T;
@ -38,7 +38,7 @@ export type RelationChecker<ED extends EntityDict, T extends keyof ED, Cxt exten
errMsg: string;
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter'] | Promise<ED[T]['Selection']['filter']>);
};
export type LogicalChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
export declare type LogicalChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
priority?: number;
type: 'logical';
when?: 'after';
@ -47,7 +47,7 @@ export type LogicalChecker<ED extends EntityDict, T extends keyof ED, Cxt extend
checker: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => void | Promise<void>;
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
};
export type LogicalRelationChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
export declare type LogicalRelationChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
priority?: number;
type: 'logicalRelation';
when?: 'after';
@ -56,11 +56,11 @@ export type LogicalRelationChecker<ED extends EntityDict, T extends keyof ED, Cx
checker: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => void | Promise<void>;
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
};
export type Checker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = DataChecker<ED, T, Cxt> | RowChecker<ED, T, Cxt> | RelationChecker<ED, T, Cxt> | LogicalChecker<ED, T, Cxt> | LogicalRelationChecker<ED, T, Cxt>;
export type AuthDef<ED extends EntityDict, T extends keyof ED> = {
export declare type Checker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = DataChecker<ED, T, Cxt> | RowChecker<ED, T, Cxt> | RelationChecker<ED, T, Cxt> | LogicalChecker<ED, T, Cxt> | LogicalRelationChecker<ED, T, Cxt>;
export declare type AuthDef<ED extends EntityDict, T extends keyof ED> = {
relationAuth?: CascadeRelationAuth<NonNullable<ED[T]['Relation']>>;
actionAuth?: CascadeActionAuth<ED[T]['Action']>;
};
export type AuthDefDict<ED extends EntityDict> = {
export declare type AuthDefDict<ED extends EntityDict> = {
[K in keyof ED]?: AuthDef<ED, K>;
};

View File

@ -1,18 +1,18 @@
import { Geo, SingleGeo } from "./Geo";
export type Int<L extends 1 | 2 | 4 | 8> = number;
export type Uint<L extends 1 | 2 | 4 | 8> = number;
export type Double<P extends number, S extends number> = number;
export type Float<P extends number, S extends number> = number;
export type String<L extends number> = string;
export type Text = string;
export type Image = string;
export type File = string;
export type Datetime = number | Date;
export type Boolean = boolean;
export type PrimaryKey = string;
export type ForeignKey<E extends string> = string;
export type Sequence = string;
export declare type Int<L extends 1 | 2 | 4 | 8> = number;
export declare type Uint<L extends 1 | 2 | 4 | 8> = number;
export declare type Double<P extends number, S extends number> = number;
export declare type Float<P extends number, S extends number> = number;
export declare type String<L extends number> = string;
export declare type Text = string;
export declare type Image = string;
export declare type File = string;
export declare type Datetime = number | Date;
export declare type Boolean = boolean;
export declare type PrimaryKey = string;
export declare type ForeignKey<E extends string> = string;
export declare type Sequence = string;
export { Geo, SingleGeo } from './Geo';
export type DataTypes = number | string | Datetime | Geo | Object | SingleGeo;
export declare type DataTypes = number | string | Datetime | Geo | Object | SingleGeo;
export declare const types: string[];
export declare const unIndexedTypes: string[];

46
lib/types/Demand.d.ts vendored
View File

@ -1,12 +1,12 @@
import { RefOrExpression } from "./Expression";
import { OneOf } from "./Polyfill";
export declare const EXPRESSION_PREFIX = "$expr";
export type NodeId = `node-${number}`;
export type ExpressionKey = '$expr' | '$expr1' | '$expr2' | '$expr3' | '$expr4' | '$expr5' | '$expr6' | '$expr7' | '$expr8' | '$expr9' | '$expr10' | '$expr11' | '$expr12' | '$expr13' | '$expr14' | '$expr15' | '$expr16' | '$expr17' | '$expr18' | '$expr19' | '$expr20';
export type ExprOp<A> = {
export declare type NodeId = `node-${number}`;
export declare type ExpressionKey = '$expr' | '$expr1' | '$expr2' | '$expr3' | '$expr4' | '$expr5' | '$expr6' | '$expr7' | '$expr8' | '$expr9' | '$expr10' | '$expr11' | '$expr12' | '$expr13' | '$expr14' | '$expr15' | '$expr16' | '$expr17' | '$expr18' | '$expr19' | '$expr20';
export declare type ExprOp<A> = {
[K in ExpressionKey]: RefOrExpression<A>;
};
export type Q_NumberComparisonValue = number | OneOf<{
export declare type Q_NumberComparisonValue = number | OneOf<{
$gt: number;
$lt: number;
$gte: number;
@ -17,7 +17,7 @@ export type Q_NumberComparisonValue = number | OneOf<{
$nin: number[];
$between: [number, number];
}>;
export type Q_StringComparisonValue = string | OneOf<{
export declare type Q_StringComparisonValue = string | OneOf<{
$gt: string;
$lt: string;
$gte: string;
@ -30,44 +30,44 @@ export type Q_StringComparisonValue = string | OneOf<{
$in: string[];
$nin: string[];
}>;
export type Q_BooleanComparisonValue = boolean;
export type Q_DateComparisonValue = Q_NumberComparisonValue;
export type Q_EnumComparisonValue<E> = E | OneOf<{
export declare type Q_BooleanComparisonValue = boolean;
export declare type Q_DateComparisonValue = Q_NumberComparisonValue;
export declare type Q_EnumComparisonValue<E> = E | OneOf<{
$in: E[];
$nin: E[];
}>;
export type Q_ExistsValue = {
export declare type Q_ExistsValue = {
$exists: boolean;
};
export type Q_NumberValue = Q_NumberComparisonValue | Q_ExistsValue;
export type Q_StringValue = Q_StringComparisonValue | Q_ExistsValue;
export type Q_BooleanValue = Q_BooleanComparisonValue | Q_ExistsValue;
export type Q_DateValue = Q_DateComparisonValue | Q_ExistsValue;
export type Q_EnumValue<E> = Q_EnumComparisonValue<E> | Q_ExistsValue;
export type Q_State<S> = S | {
export declare type Q_NumberValue = Q_NumberComparisonValue | Q_ExistsValue;
export declare type Q_StringValue = Q_StringComparisonValue | Q_ExistsValue;
export declare type Q_BooleanValue = Q_BooleanComparisonValue | Q_ExistsValue;
export declare type Q_DateValue = Q_DateComparisonValue | Q_ExistsValue;
export declare type Q_EnumValue<E> = Q_EnumComparisonValue<E> | Q_ExistsValue;
export declare type Q_State<S> = S | {
$in: S[];
} | {
$nin: S[];
} | Q_ExistsValue;
export type Q_FullTextValue = {
export declare type Q_FullTextValue = {
$search: string;
$language?: 'zh_CN' | 'en_US';
};
export type Q_FullTextKey = '$text';
export type FulltextFilter = {
export declare type Q_FullTextKey = '$text';
export declare type FulltextFilter = {
[F in Q_FullTextKey]?: Q_FullTextValue;
};
type Q_LogicKey = '$and' | '$or';
type Q_LinearLogicKey = '$not';
export type MakeFilterWrapper<F extends Object> = {
declare type Q_LogicKey = '$and' | '$or';
declare type Q_LinearLogicKey = '$not';
export declare type MakeFilterWrapper<F extends Object> = {
[Q in Q_LogicKey]?: Array<MakeFilterWrapper<F>>;
} & {
[Q in Q_LinearLogicKey]?: MakeFilterWrapper<F>;
} & Partial<F>;
export type MakeFilter<F extends Object> = {
export declare type MakeFilter<F extends Object> = {
'#id'?: NodeId;
} & MakeFilterWrapper<F>;
export type RefAttr<A> = {
export declare type RefAttr<A> = {
'#attr': A;
} | {
'#refId': NodeId;

View File

@ -8,4 +8,4 @@ export interface EndpointItem<ED extends EntityDict, BackCxt extends AsyncContex
method: 'get' | 'post' | 'put' | 'delete';
fn: (context: BackCxt, params: Record<string, string>, headers: IncomingHttpHeaders, req: IncomingMessage, body?: any) => Promise<any>;
}
export type Endpoint<ED extends EntityDict, BackCxt extends AsyncContext<ED>> = EndpointItem<ED, BackCxt> | EndpointItem<ED, BackCxt>[];
export declare type Endpoint<ED extends EntityDict, BackCxt extends AsyncContext<ED>> = EndpointItem<ED, BackCxt> | EndpointItem<ED, BackCxt>[];

101
lib/types/Entity.d.ts vendored
View File

@ -1,11 +1,12 @@
import { ReadOnlyAction } from '../actions/action';
import { PrimaryKey, Sequence } from './DataType';
type TriggerDataAttributeType = '$$triggerData$$';
type TriggerTimestampAttributeType = '$$triggerTimestamp$$';
type PrimaryKeyAttributeType = 'id';
type CreateAtAttributeType = '$$createAt$$';
type UpdateAtAttributeType = '$$updateAt$$';
type DeleteAtAttributeType = '$$deleteAt$$';
type SeqAttributeType = '$$seq$$';
declare type TriggerDataAttributeType = '$$triggerData$$';
declare type TriggerTimestampAttributeType = '$$triggerTimestamp$$';
declare type PrimaryKeyAttributeType = 'id';
declare type CreateAtAttributeType = '$$createAt$$';
declare type UpdateAtAttributeType = '$$updateAt$$';
declare type DeleteAtAttributeType = '$$deleteAt$$';
declare type SeqAttributeType = '$$seq$$';
export declare const TriggerDataAttribute = "$$triggerData$$";
export declare const TriggerTimestampAttribute = "$$triggerTimestamp$$";
export declare const PrimaryKeyAttribute = "id";
@ -13,14 +14,14 @@ export declare const CreateAtAttribute = "$$createAt$$";
export declare const UpdateAtAttribute = "$$updateAt$$";
export declare const DeleteAtAttribute = "$$deleteAt$$";
export declare const SeqAttribute = "$$seq$$";
export type InstinctiveAttributes = PrimaryKeyAttributeType | CreateAtAttributeType | UpdateAtAttributeType | DeleteAtAttributeType | TriggerDataAttributeType | TriggerTimestampAttributeType | SeqAttributeType;
export declare type InstinctiveAttributes = PrimaryKeyAttributeType | CreateAtAttributeType | UpdateAtAttributeType | DeleteAtAttributeType | TriggerDataAttributeType | TriggerTimestampAttributeType | SeqAttributeType;
export declare const initinctiveAttributes: string[];
type FilterPart<A extends string, F extends Object | undefined> = {
declare type FilterPart<A extends string, F extends Object | undefined> = {
filter?: A extends 'create' ? undefined : F;
indexFrom?: A extends 'create' ? undefined : number;
count?: A extends 'create' ? undefined : number;
};
export type SelectOption = {
export declare type SelectOption = {
dontCollect?: boolean;
blockTrigger?: true;
obscure?: boolean;
@ -28,7 +29,7 @@ export type SelectOption = {
includedDeleted?: true;
dummy?: 1;
};
export type OperateOption = {
export declare type OperateOption = {
blockTrigger?: true;
dontCollect?: boolean;
dontCreateOper?: boolean;
@ -38,13 +39,19 @@ export type OperateOption = {
modiParentEntity?: string;
dummy?: 1;
};
export type FormUpdateData<SH extends GeneralEntityShape> = Partial<{
export declare type FormUpdateData<SH extends GeneralEntityShape> = Partial<{
[K in keyof Omit<SH, InstinctiveAttributes>]: SH[K] | null;
}>;
export type FormCreateData<SH extends GeneralEntityShape> = Partial<Omit<SH, InstinctiveAttributes>> & {
export declare type FormCreateData<SH extends GeneralEntityShape> = Partial<Omit<SH, InstinctiveAttributes>> & {
id: string;
};
export type Operation<A extends string, D extends Projection, F extends Filter | undefined = undefined, S extends Sorter | undefined = undefined> = {
export declare type Operation<A extends string, D extends Projection, F extends Filter | undefined = undefined, S extends Sorter | undefined = undefined> = {
id: string;
action: A;
data: D;
sorter?: S;
} & FilterPart<A, F>;
export declare type Selection<A extends ReadOnlyAction, D extends Projection, F extends Filter | undefined = undefined, S extends Sorter | undefined = undefined> = {
id?: string;
action: A;
data: D;
@ -60,14 +67,14 @@ export interface EntityShape {
interface GeneralEntityShape extends EntityShape {
[K: string]: any;
}
export type MakeAction<A extends string> = A;
export declare type MakeAction<A extends string> = A;
export interface EntityDef {
Schema: GeneralEntityShape;
OpSchema: GeneralEntityShape;
Action: string;
ParticularAction?: string;
Selection: Omit<Operation<'select', Projection, Filter, Sorter>, 'action'>;
Aggregation: Omit<DeduceAggregation<Projection, Filter, Sorter>, 'action'>;
Selection: Omit<Selection<'select', Projection, Filter, Sorter>, 'action'>;
Aggregation: DeduceAggregation<Projection, Filter, Sorter>;
Operation: CUDOperation;
Create: CreateOperation;
CreateSingle: CreateSingleOperation;
@ -82,79 +89,79 @@ export interface EntityDict {
export interface OtmSubProjection extends Omit<Operation<'select', any, any, any>, 'action'> {
$entity: string;
}
export type AggregationOp = `#max-${number}` | `#min-${number}` | `#avg-${number}` | `#count-${number}` | `#sum-${number}`;
export type DeduceAggregationData<P extends Projection> = {
export declare type AggregationOp = `#max-${number}` | `#min-${number}` | `#avg-${number}` | `#count-${number}` | `#sum-${number}`;
export declare type DeduceAggregationData<P extends Projection> = {
[A in AggregationOp]?: P;
} & {
'#aggr'?: P;
};
export type AggregationResult<SH extends GeneralEntityShape> = Array<{
export declare type AggregationResult<SH extends GeneralEntityShape> = Array<{
[A in AggregationOp]?: number | string;
} & {
'#data'?: Partial<SH>;
}>;
export type AttrFilter<SH extends GeneralEntityShape> = {
export declare type AttrFilter<SH extends GeneralEntityShape> = {
[K in keyof SH]?: any;
};
type SortAttr = {
declare type SortAttr = {
[K: string]: any;
};
type SorterItem = {
declare type SorterItem = {
$attr: SortAttr;
$direction?: "asc" | "desc";
};
type Sorter = Array<SorterItem>;
type Filter = {
declare type Sorter = Array<SorterItem>;
declare type Filter = {
[K: string]: any;
};
type Projection = {
declare type Projection = {
[K: string]: any;
};
export type DeduceAggregation<P extends Projection, F extends Filter, S extends Sorter> = Omit<Operation<'aggregate', DeduceAggregationData<P>, F, S>, 'action'>;
type CreateOperationData = {
export declare type DeduceAggregation<P extends Projection, F extends Filter, S extends Sorter> = Omit<Selection<'aggregate', DeduceAggregationData<P>, F, S>, 'action'>;
declare type CreateOperationData = {
id: string;
[K: string]: any;
};
type CreateSingleOperation = Operation<'create', CreateOperationData, undefined, undefined>;
type CreateMultipleOperation = Operation<'create', Array<CreateOperationData>, undefined, undefined>;
type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
type UpdateOperationData = {
declare type CreateSingleOperation = Operation<'create', CreateOperationData, undefined, undefined>;
declare type CreateMultipleOperation = Operation<'create', Array<CreateOperationData>, undefined, undefined>;
declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
declare type UpdateOperationData = {
id?: never;
[k: string]: any;
};
export type UpdateOperation = Operation<string, UpdateOperationData, Filter, Sorter>;
type RemoveOperationData = {
export declare type UpdateOperation = Operation<string, UpdateOperationData, Filter, Sorter>;
declare type RemoveOperationData = {
[k: string]: any;
};
export type RemoveOperation = Operation<'remove', RemoveOperationData, Filter, Sorter>;
export type CUDOperation = CreateOperation | UpdateOperation | RemoveOperation;
export type CreateOpResult<ED extends EntityDict, T extends keyof ED> = {
export declare type RemoveOperation = Operation<'remove', RemoveOperationData, Filter, Sorter>;
export declare type CUDOperation = CreateOperation | UpdateOperation | RemoveOperation;
export declare type CreateOpResult<ED extends EntityDict, T extends keyof ED> = {
a: 'c';
e: T;
d: ED[T]['OpSchema'] | ED[T]['OpSchema'][];
};
export type UpdateOpResult<ED extends EntityDict, T extends keyof ED> = {
export declare type UpdateOpResult<ED extends EntityDict, T extends keyof ED> = {
a: 'u';
e: T;
d: UpdateOperationData;
f?: Filter;
};
export type RemoveOpResult<ED extends EntityDict, T extends keyof ED> = {
export declare type RemoveOpResult<ED extends EntityDict, T extends keyof ED> = {
a: 'r';
e: T;
f?: Filter;
};
export type RelationHierarchy<R extends string> = {
export declare type RelationHierarchy<R extends string> = {
[K in R]?: R[];
};
export type CascadeRelationItem = {
export declare type CascadeRelationItem = {
cascadePath: string;
relations?: string[];
};
export type CascadeRelationAuth<R extends string> = {
export declare type CascadeRelationAuth<R extends string> = {
[K in R]?: CascadeRelationItem | (CascadeRelationItem | CascadeRelationItem[])[];
};
export type SelectOpResult<ED extends EntityDict> = {
export declare type SelectOpResult<ED extends EntityDict> = {
a: 's';
d: {
[T in keyof ED]?: {
@ -162,14 +169,14 @@ export type SelectOpResult<ED extends EntityDict> = {
};
};
};
export type OpRecord<ED extends EntityDict> = CreateOpResult<ED, keyof ED> | UpdateOpResult<ED, keyof ED> | RemoveOpResult<ED, keyof ED> | SelectOpResult<ED>;
export type OperationResult<ED extends EntityDict> = {
export declare type OpRecord<ED extends EntityDict> = CreateOpResult<ED, keyof ED> | UpdateOpResult<ED, keyof ED> | RemoveOpResult<ED, keyof ED> | SelectOpResult<ED>;
export declare type OperationResult<ED extends EntityDict> = {
[K in keyof ED]?: {
[A in ED[K]['Action']]?: number;
};
};
export type ActionType = 'readOnly' | 'appendOnly' | 'excludeUpdate' | 'excludeRemove' | 'crud';
export type Configuration = {
export declare type ActionType = 'readOnly' | 'appendOnly' | 'excludeUpdate' | 'excludeRemove' | 'crud';
export declare type Configuration = {
actionType?: ActionType;
static?: boolean;
};

View File

@ -5,6 +5,16 @@ export declare class OakException extends Error {
}
export declare class OakDataException extends OakException {
}
export declare class OakUniqueViolationException extends OakException {
rows: Array<{
id?: string;
attrs: string[];
}>;
constructor(rows: Array<{
id?: string;
attrs: string[];
}>, message?: string);
}
export declare class OakImportDataParseException extends OakException {
line: number;
header?: string;

View File

@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeException = exports.OakDeadlock = exports.OakCongruentRowExists = exports.OakRowLockedException = exports.OakUnloggedInException = exports.OakUserUnpermittedException = exports.OakInputIllegalException = exports.OakRowInconsistencyException = exports.OakUserException = exports.OakExternalException = exports.OakRowUnexistedException = exports.OakOperExistedException = exports.OakImportDataParseException = exports.OakDataException = exports.OakException = void 0;
exports.makeException = exports.OakDeadlock = exports.OakCongruentRowExists = exports.OakRowLockedException = exports.OakUnloggedInException = exports.OakUserUnpermittedException = exports.OakInputIllegalException = exports.OakRowInconsistencyException = exports.OakUserException = exports.OakExternalException = exports.OakRowUnexistedException = exports.OakOperExistedException = exports.OakImportDataParseException = exports.OakUniqueViolationException = exports.OakDataException = exports.OakException = void 0;
var tslib_1 = require("tslib");
var OakException = /** @class */ (function (_super) {
tslib_1.__extends(OakException, _super);
@ -36,6 +36,16 @@ var OakDataException = /** @class */ (function (_super) {
return OakDataException;
}(OakException));
exports.OakDataException = OakDataException;
var OakUniqueViolationException = /** @class */ (function (_super) {
tslib_1.__extends(OakUniqueViolationException, _super);
function OakUniqueViolationException(rows, message) {
var _this = _super.call(this, message || '您更新的数据违反了唯一性约束') || this;
_this.rows = rows;
return _this;
}
return OakUniqueViolationException;
}(OakException));
exports.OakUniqueViolationException = OakUniqueViolationException;
var OakImportDataParseException = /** @class */ (function (_super) {
tslib_1.__extends(OakImportDataParseException, _super);
// message必传描述具体错误的数据内容
@ -257,6 +267,12 @@ function makeException(data) {
case 'OakDeadlock': {
return new OakDeadlock(data.message);
}
case 'OakDataException': {
return new OakDataException(data.message);
}
case 'OakUniqueViolationException': {
return new OakUniqueViolationException(data.rows, data.message);
}
case 'OakImportDataParseException': {
return new OakImportDataParseException(data.message, data.line, data.header);
}

View File

@ -1,8 +1,8 @@
import { RefAttr } from "./Demand";
import { Geo } from "./Geo";
export type RefOrExpression<A> = RefAttr<A> | Expression<A>;
type MathType<A> = RefOrExpression<A> | number;
type StringType<A> = RefOrExpression<A> | string;
export declare type RefOrExpression<A> = RefAttr<A> | Expression<A>;
declare type MathType<A> = RefOrExpression<A> | number;
declare type StringType<A> = RefOrExpression<A> | string;
interface Add<A> {
$add: (MathType<A>)[];
}
@ -30,8 +30,8 @@ interface Ceil<A> {
interface Pow<A> {
$pow: [MathType<A>, MathType<A>];
}
type MathExpression<A> = Add<A> | Subtract<A> | Multiply<A> | Divide<A> | Abs<A> | Round<A> | Floor<A> | Ceil<A> | Pow<A>;
type CmpType<A> = RefOrExpression<A> | string | number;
declare type MathExpression<A> = Add<A> | Subtract<A> | Multiply<A> | Divide<A> | Abs<A> | Round<A> | Floor<A> | Ceil<A> | Pow<A>;
declare type CmpType<A> = RefOrExpression<A> | string | number;
interface Gt<A> {
$gt: [CmpType<A>, CmpType<A>];
}
@ -59,14 +59,14 @@ interface EndsWith<A> {
interface Includes<A> {
$includes: [RefOrExpression<A> | string, RefOrExpression<A> | string];
}
type CompareExpression<A> = Lt<A> | Gt<A> | Lte<A> | Gte<A> | Eq<A> | Ne<A> | StartsWith<A> | EndsWith<A> | Includes<A>;
declare type CompareExpression<A> = Lt<A> | Gt<A> | Lte<A> | Gte<A> | Eq<A> | Ne<A> | StartsWith<A> | EndsWith<A> | Includes<A>;
interface BoolTrue<A> {
$true: Expression<A>;
}
interface BoolFalse<A> {
$false: Expression<A>;
}
type BoolExpression<A> = BoolTrue<A> | BoolFalse<A>;
declare type BoolExpression<A> = BoolTrue<A> | BoolFalse<A>;
interface LogicAnd<A> {
$and: Expression<A>[];
}
@ -76,7 +76,7 @@ interface LogicOr<A> {
interface LogicNot<A> {
$not: Expression<A>;
}
type LogicExpression<A> = LogicAnd<A> | LogicOr<A> | LogicNot<A>;
declare type LogicExpression<A> = LogicAnd<A> | LogicOr<A> | LogicNot<A>;
interface DateYear<A> {
$year: RefOrExpression<A> | Date | number;
}
@ -110,18 +110,18 @@ interface DateCeiling<A> {
interface DateFloor<A> {
$dateFloor: [RefOrExpression<A> | Date | number, 'y' | 'M' | 'd' | 'h' | 'm' | 's'];
}
type DateExpression<A> = DateYear<A> | DateMonth<A> | DateWeekday<A> | DateWeekOfYear<A> | DateDay<A> | DateDayOfYear<A> | DateDayOfMonth<A> | DateDayOfWeek<A> | DateDiff<A> | DateCeiling<A> | DateFloor<A>;
declare type DateExpression<A> = DateYear<A> | DateMonth<A> | DateWeekday<A> | DateWeekOfYear<A> | DateDay<A> | DateDayOfYear<A> | DateDayOfMonth<A> | DateDayOfWeek<A> | DateDiff<A> | DateCeiling<A> | DateFloor<A>;
interface StringConcat<A> {
$concat: StringType<A>[];
}
type StringExpression<A> = StringConcat<A>;
declare type StringExpression<A> = StringConcat<A>;
interface GeoContains<A> {
$contains: [RefOrExpression<A> | Geo, RefOrExpression<A> | Geo];
}
interface GeoDistance<A> {
$distance: [RefOrExpression<A> | Geo, RefOrExpression<A> | Geo];
}
type GeoExpression<A> = GeoContains<A> | GeoDistance<A>;
declare type GeoExpression<A> = GeoContains<A> | GeoDistance<A>;
interface AggrCountExpression<A> {
$$count: RefOrExpression<A>;
}
@ -137,9 +137,9 @@ interface AggrMinExpression<A> {
interface AggrAvgExpression<A> {
$$avg: RefOrExpression<A>;
}
export type AggrExpression<A> = AggrAvgExpression<A> | AggrCountExpression<A> | AggrSumExpression<A> | AggrMaxExpression<A> | AggrMinExpression<A>;
export type Expression<A> = GeoExpression<A> | DateExpression<A> | LogicExpression<A> | BoolExpression<A> | CompareExpression<A> | MathExpression<A> | StringExpression<A> | AggrExpression<A>;
export type ExpressionConstant = Geo | number | Date | string | boolean;
export declare type AggrExpression<A> = AggrAvgExpression<A> | AggrCountExpression<A> | AggrSumExpression<A> | AggrMaxExpression<A> | AggrMinExpression<A>;
export declare type Expression<A> = GeoExpression<A> | DateExpression<A> | LogicExpression<A> | BoolExpression<A> | CompareExpression<A> | MathExpression<A> | StringExpression<A> | AggrExpression<A>;
export declare type ExpressionConstant = Geo | number | Date | string | boolean;
export declare function isGeoExpression<A>(expression: any): expression is GeoExpression<A>;
export declare function isDateExpression<A>(expression: any): expression is DateExpression<A>;
export declare function isLogicExpression<A>(expression: any): expression is LogicExpression<A>;

12
lib/types/Geo.d.ts vendored
View File

@ -1,8 +1,8 @@
export type Point = [number, number];
export type Path = Array<Point>;
export type Polygon = Array<Path>;
export type Circle = [Point, number];
export type SingleGeo = {
export declare type Point = [number, number];
export declare type Path = Array<Point>;
export declare type Polygon = Array<Path>;
export declare type Circle = [Point, number];
export declare type SingleGeo = {
type: 'point';
coordinate: Point;
} | {
@ -15,4 +15,4 @@ export type SingleGeo = {
type: 'circle';
coordinate: Circle;
};
export type Geo = SingleGeo | SingleGeo[];
export declare type Geo = SingleGeo | SingleGeo[];

10
lib/types/Locale.d.ts vendored
View File

@ -1,17 +1,17 @@
import { EntityShape } from "./Entity";
type Language = 'zh_CN' | 'en_US';
type LocaleOfSchema<S extends Record<string, any>> = {
declare type Language = 'zh_CN' | 'en_US';
declare type LocaleOfSchema<S extends Record<string, any>> = {
[A in keyof Required<Omit<S, keyof EntityShape>>]: string;
};
type LocaleOfStringEnum<A extends string> = {
declare type LocaleOfStringEnum<A extends string> = {
[K in A]: string;
};
type LocaleOfValue<V extends Record<string, string>> = {
declare type LocaleOfValue<V extends Record<string, string>> = {
[K in keyof V]: {
[K2 in V[K]]: string;
};
};
export type LocaleDef<Sc extends Record<string, any>, Ac extends string, R extends string, V extends Record<string, string>> = {
export declare type LocaleDef<Sc extends Record<string, any>, Ac extends string, R extends string, V extends Record<string, string>> = {
[L in Language]?: {
attr: LocaleOfSchema<Sc> & {
[A in keyof V]: string;

View File

@ -1,23 +1,23 @@
export type OmitInferKey<T, R> = {
export declare type OmitInferKey<T, R> = {
[K in keyof T as T extends R ? never : K]: T[K];
};
export type OmitInferValue<T, R> = {
export declare type OmitInferValue<T, R> = {
[K in keyof T as T extends R ? never : K]: T[K];
};
export type ValueOf<Obj> = Obj[keyof Obj];
export type OneOnly<Obj, Key extends keyof Obj> = {
export declare type ValueOf<Obj> = Obj[keyof Obj];
export declare type OneOnly<Obj, Key extends keyof Obj> = {
[key in Exclude<keyof Obj, Key>]?: undefined;
} & Pick<Obj, Key>;
export type OneOfByKey<Obj> = {
export declare type OneOfByKey<Obj> = {
[key in keyof Obj]: OneOnly<Obj, key>;
};
export type OneOf<Obj> = ValueOf<OneOfByKey<Obj>>;
type IsOptional<T, K extends keyof T> = {
export declare type OneOf<Obj> = ValueOf<OneOfByKey<Obj>>;
declare type IsOptional<T, K extends keyof T> = {
[K1 in Exclude<keyof T, K>]: T[K1];
} & {
K?: T[K];
} extends T ? K : never;
export type OptionalKeys<T> = {
export declare type OptionalKeys<T> = {
[K in keyof T]: IsOptional<T, K>;
}[keyof T];
export {};

4
lib/types/Port.d.ts vendored
View File

@ -1,6 +1,6 @@
import { AsyncContext } from "../store/AsyncRowStore";
import { EntityDict } from "./Entity";
export type Exportation<ED extends EntityDict, T extends keyof ED, K extends string> = {
export declare type Exportation<ED extends EntityDict, T extends keyof ED, K extends string> = {
name: string;
id: string;
entity: T;
@ -8,7 +8,7 @@ export type Exportation<ED extends EntityDict, T extends keyof ED, K extends str
headers: K[];
fn: (data: ED[T]['Schema']) => Partial<Record<K, string | number | boolean | null>>;
};
export type Importation<ED extends EntityDict, T extends keyof ED, K extends string> = {
export declare type Importation<ED extends EntityDict, T extends keyof ED, K extends string> = {
name: string;
id: string;
entity: T;

View File

@ -1,6 +1,6 @@
import { OperationResult, EntityDict } from './Entity';
import { StorageSchema } from './Storage';
export type TxnOption = {
export declare type TxnOption = {
isolationLevel: 'repeatable read' | 'serializable';
};
export declare abstract class RowStore<ED extends EntityDict> {

View File

@ -1,7 +1,7 @@
import { ActionType } from '.';
import { EntityDict, EntityShape, InstinctiveAttributes } from './Entity';
import { DataType, DataTypeParams } from './schema/DataTypes';
export type Ref = 'ref';
export declare type Ref = 'ref';
export interface Column<SH extends EntityShape> {
name: keyof SH | `${string}State`;
size?: number;
@ -27,12 +27,12 @@ export interface Attribute {
unique?: boolean;
sequenceStart?: number;
}
export type Attributes<SH extends EntityShape> = Omit<{
export declare type Attributes<SH extends EntityShape> = Omit<{
[attrName in keyof SH]: Attribute;
}, InstinctiveAttributes>;
export interface EntityConfig {
}
export type UniqConstraint<SH extends EntityShape> = {
export declare type UniqConstraint<SH extends EntityShape> = {
attributes: Array<keyof SH>;
type?: string;
};
@ -51,6 +51,6 @@ export interface StorageDesc<SH extends EntityShape> {
relation?: string[];
view?: true;
}
export type StorageSchema<ED extends EntityDict> = {
export declare type StorageSchema<ED extends EntityDict> = {
[K in keyof ED]: StorageDesc<ED[K]['OpSchema']>;
};

View File

@ -1,11 +1,11 @@
import { EntityDict } from './Entity';
import { AsyncContext } from "../store/AsyncRowStore";
type RoutineFn<ED extends EntityDict, Cxt extends AsyncContext<ED>> = (context: Cxt) => Promise<string>;
export type Routine<ED extends EntityDict, Cxt extends AsyncContext<ED>> = {
declare type RoutineFn<ED extends EntityDict, Cxt extends AsyncContext<ED>> = (context: Cxt) => Promise<string>;
export declare type Routine<ED extends EntityDict, Cxt extends AsyncContext<ED>> = {
name: string;
fn: RoutineFn<ED, Cxt>;
};
export type Timer<ED extends EntityDict, Cxt extends AsyncContext<ED>> = {
export declare type Timer<ED extends EntityDict, Cxt extends AsyncContext<ED>> = {
name: string;
cron: string;
fn: RoutineFn<ED, Cxt>;

View File

@ -24,7 +24,7 @@ export interface CreateTriggerCrossTxn<ED extends EntityDict, T extends keyof ED
when: 'commit';
strict?: 'takeEasy' | 'makeSure';
}
export type CreateTrigger<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = CreateTriggerInTxn<ED, T, Cxt> | CreateTriggerCrossTxn<ED, T, Cxt>;
export declare type CreateTrigger<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = CreateTriggerInTxn<ED, T, Cxt> | CreateTriggerCrossTxn<ED, T, Cxt>;
/**
* update trigger如果带有filter
* filter条件和trigger所定义的filter是否有交集
@ -46,7 +46,7 @@ export interface UpdateTriggerCrossTxn<ED extends EntityDict, T extends keyof ED
when: 'commit';
strict?: 'takeEasy' | 'makeSure';
}
export type UpdateTrigger<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = UpdateTriggerInTxn<ED, T, Cxt> | UpdateTriggerCrossTxn<ED, T, Cxt>;
export declare type UpdateTrigger<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = UpdateTriggerInTxn<ED, T, Cxt> | UpdateTriggerCrossTxn<ED, T, Cxt>;
/**
* update trigger一样remove trigger如果带有filter
* filter条件和trigger所定义的filter是否有交集
@ -67,7 +67,7 @@ export interface RemoveTriggerCrossTxn<ED extends EntityDict, T extends keyof ED
when: 'commit';
strict?: 'takeEasy' | 'makeSure';
}
export type RemoveTrigger<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = RemoveTriggerInTxn<ED, T, Cxt> | RemoveTriggerCrossTxn<ED, T, Cxt>;
export declare type RemoveTrigger<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = RemoveTriggerInTxn<ED, T, Cxt> | RemoveTriggerCrossTxn<ED, T, Cxt>;
export interface SelectTriggerBase<ED extends EntityDict, T extends keyof ED> extends TriggerBase<ED, T> {
action: 'select';
}
@ -88,8 +88,8 @@ export interface SelectTriggerAfter<ED extends EntityDict, T extends keyof ED, C
result: Partial<ED[T]['Schema']>[];
}, context: Cxt, params?: SelectOption) => Promise<number> | number;
}
export type SelectTrigger<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = SelectTriggerBefore<ED, T, Cxt> | SelectTriggerAfter<ED, T, Cxt>;
export type Trigger<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = CreateTrigger<ED, T, Cxt> | UpdateTrigger<ED, T, Cxt> | RemoveTrigger<ED, T, Cxt> | SelectTrigger<ED, T, Cxt>;
export declare type SelectTrigger<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = SelectTriggerBefore<ED, T, Cxt> | SelectTriggerAfter<ED, T, Cxt>;
export declare type Trigger<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = CreateTrigger<ED, T, Cxt> | UpdateTrigger<ED, T, Cxt> | RemoveTrigger<ED, T, Cxt> | SelectTrigger<ED, T, Cxt>;
export interface TriggerEntityShape extends EntityShape {
$$triggerData$$?: {
name: string;

View File

@ -1,6 +1,6 @@
import { AsyncContext } from "../store/AsyncRowStore";
import { EntityDict, OperationResult } from "./Entity";
type ActionData<ED extends EntityDict, T extends keyof ED> = ED[T]['Update']['data'] | ED[T]['Remove']['data'];
declare type ActionData<ED extends EntityDict, T extends keyof ED> = ED[T]['Update']['data'] | ED[T]['Remove']['data'];
export interface BBWatcher<ED extends EntityDict, T extends keyof ED> {
name: string;
entity: T;
@ -15,5 +15,5 @@ export interface WBWatcher<ED extends EntityDict, T extends keyof ED, Cxt extend
projection: ED[T]['Selection']['data'] | (() => Promise<ED[T]['Selection']['data']>);
fn: (context: Cxt, data: Partial<ED[T]['Schema']>[]) => Promise<OperationResult<ED>>;
}
export type Watcher<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED>> = BBWatcher<ED, T> | WBWatcher<ED, T, Cxt>;
export declare type Watcher<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED>> = BBWatcher<ED, T> | WBWatcher<ED, T, Cxt>;
export {};

View File

@ -1,28 +1,28 @@
/**
* Column types used for @PrimaryGeneratedColumn() decorator.
*/
export type PrimaryGeneratedColumnType = "int" | "int2" | "int4" | "int8" | "integer" | "tinyint" | "smallint" | "mediumint" | "bigint" | "dec" | "decimal" | "smalldecimal" | "fixed" | "numeric" | "number";
export declare type PrimaryGeneratedColumnType = "int" | "int2" | "int4" | "int8" | "integer" | "tinyint" | "smallint" | "mediumint" | "bigint" | "dec" | "decimal" | "smalldecimal" | "fixed" | "numeric" | "number";
/**
* Column types where spatial properties are used.
*/
export type SpatialColumnType = "geometry" | "geography" | "st_geometry" | "st_point";
export declare type SpatialColumnType = "geometry" | "geography" | "st_geometry" | "st_point";
/**
* Column types where precision and scale properties are used.
*/
export type WithPrecisionColumnType = "float" | "double" | "dec" | "decimal" | "smalldecimal" | "fixed" | "numeric" | "real" | "double precision" | "number" | "datetime" | "datetime2" | "datetimeoffset" | "time" | "time with time zone" | "time without time zone" | "timestamp" | "timestamp without time zone" | "timestamp with time zone" | "timestamp with local time zone";
export declare type WithPrecisionColumnType = "float" | "double" | "dec" | "decimal" | "smalldecimal" | "fixed" | "numeric" | "real" | "double precision" | "number" | "datetime" | "datetime2" | "datetimeoffset" | "time" | "time with time zone" | "time without time zone" | "timestamp" | "timestamp without time zone" | "timestamp with time zone" | "timestamp with local time zone";
/**
* Column types where column length is used.
*/
export type WithLengthColumnType = "character varying" | "varying character" | "char varying" | "nvarchar" | "national varchar" | "character" | "native character" | "varchar" | "char" | "nchar" | "national char" | "varchar2" | "nvarchar2" | "alphanum" | "shorttext" | "raw" | "binary" | "varbinary" | "string";
export type WithWidthColumnType = "tinyint" | "smallint" | "mediumint" | "int" | "bigint";
export declare type WithLengthColumnType = "character varying" | "varying character" | "char varying" | "nvarchar" | "national varchar" | "character" | "native character" | "varchar" | "char" | "nchar" | "national char" | "varchar2" | "nvarchar2" | "alphanum" | "shorttext" | "raw" | "binary" | "varbinary" | "string";
export declare type WithWidthColumnType = "tinyint" | "smallint" | "mediumint" | "int" | "bigint";
/**
* All other regular column types.
*/
export type SimpleColumnType = "simple-array" | "simple-json" | "simple-enum" | "int2" | "integer" | "int4" | "int8" | "int64" | "unsigned big int" | "float" | "float4" | "float8" | "smallmoney" | "money" | "boolean" | "bool" | "tinyblob" | "tinytext" | "mediumblob" | "mediumtext" | "blob" | "text" | "ntext" | "citext" | "hstore" | "longblob" | "longtext" | "alphanum" | "shorttext" | "bytes" | "bytea" | "long" | "raw" | "long raw" | "bfile" | "clob" | "nclob" | "image" | "timetz" | "timestamptz" | "timestamp with local time zone" | "smalldatetime" | "date" | "interval year to month" | "interval day to second" | "interval" | "year" | "seconddate" | "point" | "line" | "lseg" | "box" | "circle" | "path" | "polygon" | "geography" | "geometry" | "linestring" | "multipoint" | "multilinestring" | "multipolygon" | "geometrycollection" | "st_geometry" | "st_point" | "int4range" | "int8range" | "numrange" | "tsrange" | "tstzrange" | "daterange" | "enum" | "set" | "cidr" | "inet" | "macaddr" | "bit" | "bit varying" | "varbit" | "tsvector" | "tsquery" | "uuid" | "xml" | "json" | "jsonb" | "varbinary" | "hierarchyid" | "sql_variant" | "rowid" | "urowid" | "uniqueidentifier" | "rowversion" | "array" | "cube" | "ltree" | "object" | "array" | "function" | "sequence";
export declare type SimpleColumnType = "simple-array" | "simple-json" | "simple-enum" | "int2" | "integer" | "int4" | "int8" | "int64" | "unsigned big int" | "float" | "float4" | "float8" | "smallmoney" | "money" | "boolean" | "bool" | "tinyblob" | "tinytext" | "mediumblob" | "mediumtext" | "blob" | "text" | "ntext" | "citext" | "hstore" | "longblob" | "longtext" | "alphanum" | "shorttext" | "bytes" | "bytea" | "long" | "raw" | "long raw" | "bfile" | "clob" | "nclob" | "image" | "timetz" | "timestamptz" | "timestamp with local time zone" | "smalldatetime" | "date" | "interval year to month" | "interval day to second" | "interval" | "year" | "seconddate" | "point" | "line" | "lseg" | "box" | "circle" | "path" | "polygon" | "geography" | "geometry" | "linestring" | "multipoint" | "multilinestring" | "multipolygon" | "geometrycollection" | "st_geometry" | "st_point" | "int4range" | "int8range" | "numrange" | "tsrange" | "tstzrange" | "daterange" | "enum" | "set" | "cidr" | "inet" | "macaddr" | "bit" | "bit varying" | "varbit" | "tsvector" | "tsquery" | "uuid" | "xml" | "json" | "jsonb" | "varbinary" | "hierarchyid" | "sql_variant" | "rowid" | "urowid" | "uniqueidentifier" | "rowversion" | "array" | "cube" | "ltree" | "object" | "array" | "function" | "sequence";
/**
* Any column type column can be.
*/
export type DataType = WithPrecisionColumnType | WithLengthColumnType | WithWidthColumnType | SpatialColumnType | SimpleColumnType;
export declare type DataType = WithPrecisionColumnType | WithLengthColumnType | WithWidthColumnType | SpatialColumnType | SimpleColumnType;
export interface DataTypeParams {
length?: number;
width?: number;

View File

@ -1,4 +1,4 @@
type Mode = 'S' | 'X';
declare type Mode = 'S' | 'X';
/**
*
*

2
lib/utils/uuid.d.ts vendored
View File

@ -3,7 +3,7 @@ export declare function sequentialUuid({ random }: {
}): string;
export declare function shrinkUuidTo32Bytes(uuid: string): string;
export declare function expandUuidTo36Bytes(uuidShrinked: string): string;
export type GenerateIdOption = {
export declare type GenerateIdOption = {
shuffle?: boolean;
};
export declare function generateNewIdAsync(option?: GenerateIdOption): Promise<string>;

View File

@ -105,7 +105,7 @@ function sequentialUuid(_a) {
}
exports.sequentialUuid = sequentialUuid;
function shrinkUuidTo32Bytes(uuid) {
return uuid.replaceAll('-', '');
return uuid.replace(/\-/g, '');
}
exports.shrinkUuidTo32Bytes = shrinkUuidTo32Bytes;
function expandUuidTo36Bytes(uuidShrinked) {

View File

@ -1,5 +1,5 @@
type ValidatorFunction = (text: string, size?: number) => string | boolean;
type ValidatorMoneyFunction = (text: string, zero?: boolean) => string | boolean;
declare type ValidatorFunction = (text: string, size?: number) => string | boolean;
declare type ValidatorMoneyFunction = (text: string, zero?: boolean) => string | boolean;
export declare const isMobile: ValidatorFunction;
export declare const isPassword: ValidatorFunction;
export declare const isCaptcha: ValidatorFunction;

View File

@ -1,6 +1,6 @@
{
"name": "oak-domain",
"version": "2.4.1",
"version": "2.4.2",
"author": {
"name": "XuChang"
},

View File

@ -1,12 +1,12 @@
import { ActionDef } from '../types/Action';
export type ReadOnlyAction = 'select' | 'count' | 'stat' | 'download';
export type ReadOnlyAction = 'select' | 'count' | 'stat' | 'download' | 'aggregate';
export type AppendOnlyAction = ReadOnlyAction | 'create';
export type ExcludeUpdateAction = AppendOnlyAction | 'remove';
export type ExcludeRemoveAction = AppendOnlyAction | 'update';
export type GenericAction = 'update' | ExcludeUpdateAction;
export type RelationAction = 'grant' | 'revoke';
export const readOnlyActions = ['count', 'stat', 'download', 'select'];
export const readOnlyActions = ['count', 'stat', 'download', 'select', 'aggregate'];
export const appendOnlyActions = readOnlyActions.concat('create');
export const excludeUpdateActions = appendOnlyActions.concat('remove');
export const exludeRemoveActions = appendOnlyActions.concat('update');

View File

@ -1,9 +1,8 @@
import PathLib from 'path';
import assert from 'assert';
import { execSync } from 'child_process';
import { writeFileSync, readdirSync, mkdirSync, fstat } from 'fs';
import { emptydirSync } from 'fs-extra';
import { assign, cloneDeep, difference, identity, intersection, keys, uniq, uniqBy } from 'lodash';
import { assign, cloneDeep, difference, identity, intersection, keys, pull, uniq, uniqBy } from 'lodash';
import * as ts from 'typescript';
const { factory } = ts;
import {
@ -952,12 +951,12 @@ function analyzeEntity(filename: string, path: string, program: ts.Program, rela
}
) as ts.PropertyAssignment;
assert(ts.isStringLiteral(nameProperty.initializer));
const indexName = nameProperty.initializer.text;
if (indexNameDict[indexName]) {
throw new Error(`${filename}」索引定义重名「${indexName}`);
const nameText = nameProperty.initializer.text;
if (indexNameDict[nameText]) {
throw new Error(`${filename}」索引定义重名「${nameText}`);
}
assign(indexNameDict, {
[indexName]: true,
[nameText]: true,
});
const configProperty = properties.find(
@ -1010,11 +1009,11 @@ function analyzeEntity(filename: string, path: string, program: ts.Program, rela
}
) as ts.PropertySignature;
if (!schemaNode) {
throw new Error(`${filename}」中索引「${indexName}」的属性「${indexAttrName}」定义非法`);
throw new Error(`${filename}」中索引「${nameText}」的属性「${indexAttrName}」定义非法`);
}
const { type, name } = schemaNode;
const entity = firstLetterLowerCase(moduleName);
const entity = moduleName;
const { [entity]: manyToOneSet } = ManyToOne;
if (ts.isTypeReferenceNode(type!)) {
const { typeName } = type;
@ -1027,14 +1026,19 @@ function analyzeEntity(filename: string, path: string, program: ts.Program, rela
if (!manyToOneItem) {
// 如果不是外键则不能是Text, File
if (isFulltextIndex) {
assert(['Text', 'String'].includes(text2), `${filename}」中全文索引「${indexName}」定义的属性「${indexAttrName}」类型非法只能是Text/String`);
assert(['Text', 'String'].includes(text2), `${filename}」中全文索引「${nameText}」定义的属性「${indexAttrName}」类型非法只能是Text/String`);
}
else {
assert(!unIndexedTypes.includes(text2), `${filename}」中索引「${indexName}」的属性「${indexAttrName}」的类型为「${text2}」,不可索引`);
assert(!unIndexedTypes.includes(text2), `${filename}」中索引「${nameText}」的属性「${indexAttrName}」的类型为「${text2}」,不可索引`);
}
}
else {
assert(!isFulltextIndex, `${filename}」中全文索引「${indexName}」的属性「${indexAttrName}」类型非法只能为Text/String`);
assert(!isFulltextIndex, `${filename}」中全文索引「${nameText}」的属性「${indexAttrName}」类型非法只能为Text/String`);
// 在这里把外键加上Id这样storageSchema才能正常通过
// 这里的写法不太好未来TS版本高了可能会有问题。by Xc 20230131
Object.assign(nameProperty, {
initializer: factory.createStringLiteral(`${indexAttrName}Id`),
});
}
}
else {
@ -1042,8 +1046,8 @@ function analyzeEntity(filename: string, path: string, program: ts.Program, rela
}
}
else {
assert(!isFulltextIndex, `${filename}」中全文索引「${indexName}」的属性「${indexAttrName}」类型只能为Text/String`);
assert(ts.isUnionTypeNode(type!) || ts.isLiteralTypeNode(type!), `${entity}中索引「${indexName}」的属性${(<ts.Identifier>name).text}有定义非法`);
assert(!isFulltextIndex, `${filename}」中全文索引「${nameText}」的属性「${indexAttrName}」类型只能为Text/String`);
assert(ts.isUnionTypeNode(type!) || ts.isLiteralTypeNode(type!), `${entity}中索引「${nameText}」的属性${(<ts.Identifier>name).text}有定义非法`);
}
}
}
@ -1587,6 +1591,7 @@ function constructFilter(statements: Array<ts.Statement>, entity: string) {
break;
}
case 'Int':
case 'Uint':
case 'Float':
case 'Double': {
type2 = factory.createTypeReferenceNode(
@ -2814,27 +2819,21 @@ function constructActions(statements: Array<ts.Statement>, entity: string) {
)
],
factory.createTypeReferenceNode(
factory.createIdentifier("Omit"),
factory.createIdentifier("OakSelection"),
[
factory.createLiteralTypeNode(factory.createStringLiteral("select")),
factory.createTypeReferenceNode(
factory.createIdentifier("OakOperation"),
[
factory.createLiteralTypeNode(factory.createStringLiteral("select")),
factory.createTypeReferenceNode(
factory.createIdentifier("P"),
undefined
),
factory.createTypeReferenceNode(
factory.createIdentifier("Filter"),
undefined
),
factory.createTypeReferenceNode(
factory.createIdentifier("Sorter"),
undefined
)
]
factory.createIdentifier("P"),
undefined
),
factory.createLiteralTypeNode(factory.createStringLiteral("id"))
factory.createTypeReferenceNode(
factory.createIdentifier("Filter"),
undefined
),
factory.createTypeReferenceNode(
factory.createIdentifier("Sorter"),
undefined
)
]
)
),
@ -2878,26 +2877,20 @@ function constructActions(statements: Array<ts.Statement>, entity: string) {
factory.createIdentifier("Aggregation"),
undefined,
factory.createTypeReferenceNode(
factory.createIdentifier("Omit"),
factory.createIdentifier("DeduceAggregation"),
[
factory.createTypeReferenceNode(
factory.createIdentifier("DeduceAggregation"),
[
factory.createTypeReferenceNode(
factory.createIdentifier("Projection"),
undefined
),
factory.createTypeReferenceNode(
factory.createIdentifier("Filter"),
undefined
),
factory.createTypeReferenceNode(
factory.createIdentifier("Sorter"),
undefined
)
]
factory.createIdentifier("Projection"),
undefined
),
factory.createLiteralTypeNode(factory.createStringLiteral("id"))
factory.createTypeReferenceNode(
factory.createIdentifier("Filter"),
undefined
),
factory.createTypeReferenceNode(
factory.createIdentifier("Sorter"),
undefined
)
]
)
)
@ -3775,7 +3768,7 @@ function constructActions(statements: Array<ts.Statement>, entity: string) {
const entityNameLc = firstLetterLowerCase(entityName);
foreignKeySet[entityName].forEach(
(foreignKey) => {
const identifier = `${entityNameLc}s$${foreignKey}`;
const identifier = `${entityNameLc}$${foreignKey}`;
const otmCreateOperationDataNode = factory.createTypeReferenceNode(
factory.createIdentifier("Omit"),
@ -4340,6 +4333,11 @@ const initialStatements = () => [
undefined,
factory.createIdentifier('Int')
),
factory.createImportSpecifier(
false,
undefined,
factory.createIdentifier('Uint')
),
factory.createImportSpecifier(
false,
undefined,
@ -4529,6 +4527,11 @@ const initialStatements = () => [
factory.createIdentifier("Operation"),
factory.createIdentifier("OakOperation")
),
factory.createImportSpecifier(
false,
factory.createIdentifier("Selection"),
factory.createIdentifier("OakSelection")
),
factory.createImportSpecifier(
false,
factory.createIdentifier("MakeAction"),

View File

@ -669,7 +669,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
assert(relation instanceof Array);
const [entityOtm, foreignKey] = relation;
const otmOperations = data[attr];
const dealWithOneToMany = (otm: ED[keyof ED]['Update']) => {
const dealWithOneToMany = (otm: ED[keyof ED]['Update'] | ED[keyof ED]['Create']) => {
const { action: actionOtm, data: dataOtm, filter: filterOtm } = otm;
if (!foreignKey) {
// 基于entity/entityId的one-to-many
@ -692,7 +692,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
}
else if (actionOtm === 'create') {
// 这里先假设A必是update的filter上一定有id否则用户界面上应该设计不出来这样的操作
// todo 这个假设成立吗?等遇到create/create一对多的case再完善
// todo 这个假设对watcher等后台行为可能不成立等遇到create/create一对多的case再完善
const { id } = filter!;
assert(typeof id === 'string');
if (dataOtm instanceof Array) {
@ -713,11 +713,9 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
else {
// 这里先假设A必是update的filter上一定有id否则用户界面上应该设计不出来这样的操作
// 这个倒是好像不可能出现create/update的一对多如果遇到了再完善
const { id } = filter!;
Object.assign(otm, {
filter: addFilterSegment({
entity,
entityId: id,
[entity]: filter,
}, filterOtm),
});
if (action === 'remove' && actionOtm === 'update') {
@ -747,7 +745,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
}
else if (actionOtm === 'create') {
// 这里先假设A必是update的filter上一定有id否则用户界面上应该设计不出来这样的操作
// todo 这个假设成立吗等遇到create/create一对多的case再完善
// todo 这个假设在后台可能不成立,等遇到了再说
const { id } = filter!;
assert(typeof id === 'string');
if (dataOtm instanceof Array) {
@ -764,12 +762,10 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
}
}
else {
// 这里先假设A必是update的filter上一定有id否则用户界面上应该设计不出来这样的操作
// 这个倒是好像不可能出现create/update的一对多如果遇到了再完善
const { id } = filter!;
// update可能出现上层filter不是根据id的userEntityGrant的过期触发的wechatQrCode的过期见general中的userEntityGrant的trigger
Object.assign(otm, {
filter: addFilterSegment({
[foreignKey]: id,
[foreignKey.slice(0, foreignKey.length - 2)]: filter,
}, filterOtm),
});
if (action === 'remove' && actionOtm === 'update') {
@ -780,7 +776,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
}
}
afterFns.push(() => cascadeUpdate.call(this, entityOtm!, otm, context, option2));
beforeFns.push(() => cascadeUpdate.call(this, entityOtm!, otm, context, option2));
};
if (otmOperations instanceof Array) {

View File

@ -1,6 +1,8 @@
import { ActionDictOfEntityDict, BBWatcher, Checker, EntityDict, StorageSchema, Trigger, RowChecker } from "../types";
import { ActionDictOfEntityDict, BBWatcher, Checker, EntityDict, StorageSchema, Trigger, RowChecker, OakDataException, OakUniqueViolationException } from "../types";
import { SyncContext } from "./SyncRowStore";
import { AsyncContext } from "./AsyncRowStore";
import { uniqBy, pick, intersection } from '../utils/lodash';
import { addFilterSegment } from "./filter";
export function getFullProjection<ED extends EntityDict, T extends keyof ED>(entity: T, schema: StorageSchema<ED>) {
const { attributes } = schema[entity];
@ -24,18 +26,17 @@ function makeIntrinsicWatchers<ED extends EntityDict>(schema: StorageSchema<ED>)
for (const entity in schema) {
const { attributes } = schema[entity];
const now = Date.now();
const { expiresAt, expired } = attributes;
if (expiresAt && expiresAt.type === 'datetime' && expired && expired.type === 'boolean') {
// 如果有定义expiresAt和expired则自动生成一个检查的watcher
watchers.push({
entity,
name: `对象${entity}上的过期自动watcher`,
filter: async () => {
filter: () => {
return {
expired: false,
expiresAt: {
$lte: now,
$lte: Date.now(),
},
};
},
@ -50,9 +51,75 @@ function makeIntrinsicWatchers<ED extends EntityDict>(schema: StorageSchema<ED>)
return watchers;
}
function checkUniqueBetweenRows(rows: Record<string, any>[], uniqAttrs: string[]) {
// 先检查这些行本身之间有无unique冲突
const uniqRows = uniqBy(rows, (d) => {
let s = '';
for (const a of uniqAttrs) {
if (d[a as string] === null || d[a as string] === undefined) {
s + d.id;
}
else {
s + `-${d[a as string]}`;
}
}
return s;
});
if (uniqRows.length < rows.length) {
throw new OakUniqueViolationException([{
attrs: uniqAttrs,
}]);
}
}
function checkCountLessThan(count: number | Promise<number>, uniqAttrs: string[], than: number = 0, id?: string) {
if (count instanceof Promise) {
return count.then(
(count2) => {
if (count2 > than) {
throw new OakUniqueViolationException([{
id,
attrs: uniqAttrs,
}]);
}
}
)
}
if (count > than) {
throw new OakUniqueViolationException([{
id,
attrs: uniqAttrs,
}]);
}
}
function checkUnique<ED extends EntityDict, Cxt extends SyncContext<ED> | AsyncContext<ED>>(
entity: keyof ED,
row: Record<string, any>,
context: Cxt,
uniqAttrs: string[],
extraFilter?: ED[keyof ED]['Selection']['filter']
) {
const filter = pick(row, uniqAttrs);
for (const a in filter) {
if (filter[a] === null || filter[a] === undefined) {
delete filter[a];
}
}
if (Object.keys(filter).length < uniqAttrs.length) {
// 说明有null值不需要检查约束
return;
}
const filter2 = extraFilter ? addFilterSegment([filter, extraFilter]) : filter;
const count = context.count(entity, { filter: filter2 }, { dontCollect: true });
return checkCountLessThan(count, uniqAttrs, 0, row.id)
}
export function analyzeActionDefDict<ED extends EntityDict, Cxt extends SyncContext<ED> | AsyncContext<ED>>(schema: StorageSchema<ED>, actionDefDict: ActionDictOfEntityDict<ED>) {
const checkers: Array<Checker<ED, keyof ED, Cxt>> = [];
const triggers: Array<Trigger<ED, keyof ED, Cxt>> = [];
// action状态转换矩阵相应的checker
for (const entity in actionDefDict) {
for (const attr in actionDefDict[entity]) {
const def = actionDefDict[entity]![attr];
@ -92,7 +159,7 @@ export function analyzeActionDefDict<ED extends EntityDict, Cxt extends SyncCont
type: 'data',
entity,
priority: 10, // 优先级要高
checker: (data) => {
checker: (data) => {
if (data instanceof Array) {
data.forEach(
ele => {
@ -117,6 +184,125 @@ export function analyzeActionDefDict<ED extends EntityDict, Cxt extends SyncCont
}
}
// unique索引相应的checker
for (const entity in schema) {
const { indexes } = schema[entity];
if (indexes) {
for (const index of indexes) {
if (index.config?.unique) {
const { attributes } = index;
const uniqAttrs = attributes.map(ele => ele.name as string);
checkers.push({
entity,
action: 'create',
type: 'logical',
priority: 20, // 优先级要放在最高所有前置的checker/trigger将数据完整之后再在这里检测
checker: (operation, context) => {
const { data } = operation;
if (data instanceof Array) {
checkUniqueBetweenRows(data, uniqAttrs);
const checkResult = data.map(
ele => checkUnique<ED, Cxt>(entity, ele, context, uniqAttrs)
);
if (checkResult[0] instanceof Promise) {
return Promise.all(checkResult).then(
() => undefined
);
}
}
else {
return checkUnique<ED, Cxt>(entity, data, context, uniqAttrs);
}
}
}, {
entity,
action: 'update', // 只检查update其它状态转换的action应该不会涉及unique约束的属性
type: 'logical',
priority: 20, // 优先级要放在最高所有前置的checker/trigger将数据完整之后再在这里检测
checker: (operation, context) => {
const { data, filter: operationFilter } = operation as ED[keyof ED]['Update'];
const attrs = Object.keys(data);
const refAttrs = intersection(attrs, uniqAttrs);
if (refAttrs.length === 0) {
// 如果本次更新和unique约束的属性之间没有交集则直接返回
return;
}
for (const attr of refAttrs) {
// 如果有更新为null值不用再检查约束
if (data[attr as string] === null || data[attr as string] === undefined) {
return;
}
}
if (refAttrs.length === uniqAttrs.length) {
// 如果更新了全部属性,直接检查
const filter = pick(data, refAttrs);
// 在这些行以外的行不和更新后的键值冲突
const count = context.count(entity, {
filter: addFilterSegment([filter, {
$not: operationFilter,
}]),
}, { dontCollect: true });
const checkCount = checkCountLessThan(count, uniqAttrs);
// 更新的行只能有一行
const rowCount = context.count(entity, {
filter: operationFilter,
}, { dontCollect: true });
const checkRowCount = checkCountLessThan(rowCount, uniqAttrs, 1);
// 如果更新的行数为零似乎也可以但这应该不可能出现吧by Xc 20230131
if (checkRowCount instanceof Promise) {
return Promise.all([checkCount, checkRowCount]).then(
() => undefined
);
}
}
// 否则需要结合本行现有的属性来进行检查
const projection = { id: 1 };
for (const attr of uniqAttrs) {
Object.assign(projection, {
[attr]: 1,
});
}
const checkWithRows = (rows2: ED[keyof ED]['Schema'][]) => {
const rows22 = rows2.map(
ele => Object.assign(ele, data)
);
// 先检查这些行本身之间是否冲突
checkUniqueBetweenRows(rows22, uniqAttrs);
const checkResults = rows22.map(
(row) => checkUnique<ED, Cxt>(entity, row, context, uniqAttrs, {
$not: operationFilter
})
);
if (checkResults[0] instanceof Promise) {
return Promise.all(checkResults).then(
() => undefined
);
}
};
const currentRows = context.select(entity, {
data: projection,
filter: operationFilter,
}, { dontCollect: true });
if (currentRows instanceof Promise) {
return currentRows.then(
(row2) => checkWithRows(row2 as ED[keyof ED]['Schema'][])
);
}
return checkWithRows(currentRows as ED[keyof ED]['Schema'][]);
}
});
}
}
}
}
return {
triggers,
checkers,

View File

@ -24,7 +24,7 @@ const triggers: Trigger<EntityDict, 'modi', AsyncContext<EntityDict>>[] = [
for (const modi of modies) {
const { targetEntity, id, action, data, filter} = modi;
await context.operate(targetEntity as keyof EntityDict, {
id,
id: id!,
action: action as EntityDict[keyof EntityDict]['Action'],
data: data as EntityDict[keyof EntityDict]['Update']['data'],
filter: filter as EntityDict[keyof EntityDict]['Update']['filter'],

View File

@ -1,3 +1,4 @@
import { ReadOnlyAction } from '../actions/action';
import { PrimaryKey, Sequence } from './DataType';
type TriggerDataAttributeType = '$$triggerData$$';
@ -55,7 +56,17 @@ export type Operation<A extends string,
D extends Projection,
F extends Filter | undefined = undefined,
S extends Sorter | undefined = undefined> = {
id?: string; // 为了一致性每个operation也应当保证唯一id
id: string; // 为了一致性每个operation也应当保证唯一id
action: A;
data: D;
sorter?: S;
} & FilterPart<A, F>;
export type Selection<A extends ReadOnlyAction,
D extends Projection,
F extends Filter | undefined = undefined,
S extends Sorter | undefined = undefined> = {
id?: string; // selection的id可传可不传如果传意味着该select会记录在oper中
action: A;
data: D;
sorter?: S;
@ -81,8 +92,8 @@ export interface EntityDef {
OpSchema: GeneralEntityShape;
Action: string;
ParticularAction?: string;
Selection: Omit<Operation<'select', Projection, Filter, Sorter>, 'action'>;
Aggregation: Omit<DeduceAggregation<Projection, Filter, Sorter>, 'action'>;
Selection: Omit<Selection<'select', Projection, Filter, Sorter>, 'action'>;
Aggregation: DeduceAggregation<Projection, Filter, Sorter>;
Operation: CUDOperation;
Create: CreateOperation;
CreateSingle: CreateSingleOperation;
@ -140,7 +151,7 @@ type Projection = {
export type DeduceAggregation<
P extends Projection,
F extends Filter,
S extends Sorter> = Omit<Operation<'aggregate', DeduceAggregationData<P>, F, S>, 'action'>;
S extends Sorter> = Omit<Selection<'aggregate', DeduceAggregationData<P>, F, S>, 'action'>;
type CreateOperationData = {
id: string;

View File

@ -26,6 +26,20 @@ export class OakDataException extends OakException {
// 表示由数据层发现的异常
}
export class OakUniqueViolationException extends OakException {
rows: Array<{
id?: string;
attrs: string[];
}>;
constructor(rows: Array<{
id?: string;
attrs: string[];
}>, message?: string) {
super(message || '您更新的数据违反了唯一性约束');
this.rows = rows;
}
}
export class OakImportDataParseException extends OakException {
line: number;
header?: string;
@ -232,6 +246,12 @@ export function makeException(data: {
case 'OakDeadlock': {
return new OakDeadlock(data.message);
}
case 'OakDataException': {
return new OakDataException(data.message);
}
case 'OakUniqueViolationException': {
return new OakUniqueViolationException(data.rows, data.message);
}
case 'OakImportDataParseException': {
return new OakImportDataParseException(data.message!, data.line, data.header);
}

View File

@ -127,7 +127,7 @@ export function sequentialUuid({ random }: { random: Uint8Array }) {
}
export function shrinkUuidTo32Bytes(uuid: string) {
return uuid.replaceAll('-', '');
return uuid.replace(/\-/g, '');
}
export function expandUuidTo36Bytes(uuidShrinked: string) {