@pylonts/dsl 1.1.12 → 1.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/convert.d.ts +6 -8
- package/dist/curd.js +1 -1
- package/dist/dao.d.ts +10 -7
- package/dist/dao.js +20 -7
- package/dist/dsl.d.ts +18 -1
- package/dist/dsl.js +40 -0
- package/dist/dto.d.ts +13 -8
- package/dist/dto.js +68 -13
- package/dist/entity.d.ts +4 -3
- package/dist/entity.js +1 -1
- package/dist/filter.d.ts +6 -4
- package/dist/filter.js +1 -1
- package/dist/flow-script.js +8 -2
- package/dist/flow.d.ts +10 -2
- package/dist/flow.js +44 -4
- package/dist/mermaid-driver.js +2 -2
- package/dist/service.d.ts +13 -8
- package/dist/service.js +1 -1
- package/dist/third-service.d.ts +10 -53
- package/dist/third-service.js +3 -78
- package/dist/typebox-driver.d.ts +0 -6
- package/dist/typebox-driver.js +8 -36
- package/dist/utils.d.ts +2 -2
- package/docs/curd.md +146 -146
- package/docs/dao-generation.md +477 -477
- package/docs/project.md +31 -31
- package/docs/token.md +326 -326
- package/package.json +1 -1
- package/src/action.ts +51 -51
- package/src/controller.ts +53 -53
- package/src/convert.ts +76 -78
- package/src/curd.ts +104 -104
- package/src/dao.ts +504 -485
- package/src/dsl.ts +296 -257
- package/src/dto.ts +323 -266
- package/src/entity.ts +43 -42
- package/src/expr.ts +64 -64
- package/src/filter.ts +71 -69
- package/src/flow-script.ts +702 -695
- package/src/flow.ts +1272 -1226
- package/src/index.ts +46 -46
- package/src/mermaid-driver.ts +339 -339
- package/src/mysql-driver.ts +108 -108
- package/src/project.ts +138 -138
- package/src/service.ts +112 -107
- package/src/third-service.ts +68 -191
- package/src/typebox-driver.ts +234 -268
- package/src/utils.ts +74 -74
package/src/entity.ts
CHANGED
|
@@ -1,43 +1,44 @@
|
|
|
1
|
-
import type { Field, SchemaBase } from './dsl.js';
|
|
2
|
-
import type { FrontAppSchema, ProjectApiSchema } from './project.js';
|
|
3
|
-
|
|
4
|
-
/** A row object: a set of database columns. Columns may come from one table
|
|
5
|
-
* (write args of insert/update/upsert) or span tables through the main
|
|
6
|
-
* table's foreign keys (read results of find/get) — where the columns come
|
|
7
|
-
* from is the responsibility of the consuming position, not of this schema.
|
|
8
|
-
* Storage is entity_schema/{api.name}/{app.name}/entity/{table}.entity.ts:
|
|
9
|
-
* one file per table (the main table), any number of entities per file.
|
|
10
|
-
* "Row" is only a naming convention for read-shaped entities
|
|
11
|
-
* (OrderListRow, OrderDetailRow) — they are all defineEntity declarations. */
|
|
12
|
-
export interface EntitySchema extends SchemaBase {
|
|
13
|
-
type: 'entity';
|
|
14
|
-
/** The backend api module this entity belongs to (shared instance from
|
|
15
|
-
* project.config.ts apis). Entities are always backend-side. */
|
|
16
|
-
api: ProjectApiSchema;
|
|
17
|
-
/** The frontend app this entity belongs to (shared instance from project.config).
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
*
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
1
|
+
import type { Field, SchemaBase } from './dsl.js';
|
|
2
|
+
import type { FrontAppSchema, ProjectApiSchema } from './project.js';
|
|
3
|
+
|
|
4
|
+
/** A row object: a set of database columns. Columns may come from one table
|
|
5
|
+
* (write args of insert/update/upsert) or span tables through the main
|
|
6
|
+
* table's foreign keys (read results of find/get) — where the columns come
|
|
7
|
+
* from is the responsibility of the consuming position, not of this schema.
|
|
8
|
+
* Storage is entity_schema/{api.name}/{app.name}/entity/{table}.entity.ts:
|
|
9
|
+
* one file per table (the main table), any number of entities per file.
|
|
10
|
+
* "Row" is only a naming convention for read-shaped entities
|
|
11
|
+
* (OrderListRow, OrderDetailRow) — they are all defineEntity declarations. */
|
|
12
|
+
export interface EntitySchema extends SchemaBase {
|
|
13
|
+
type: 'entity';
|
|
14
|
+
/** The backend api module this entity belongs to (shared instance from
|
|
15
|
+
* project.config.ts apis). Entities are always backend-side. */
|
|
16
|
+
api: ProjectApiSchema;
|
|
17
|
+
/** The frontend app this entity belongs to (shared instance from project.config).
|
|
18
|
+
* Unset = api-level common domain entity shared by all modules of the api. */
|
|
19
|
+
app?: FrontAppSchema;
|
|
20
|
+
/** The columns of this row object: main-table columns, external reference
|
|
21
|
+
* columns, and — for aggregate result entities — aggField columns
|
|
22
|
+
* (count/sum/avg outputs). */
|
|
23
|
+
columns: Field[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function defineEntity(options: {
|
|
27
|
+
name: string;
|
|
28
|
+
api: ProjectApiSchema;
|
|
29
|
+
app?: FrontAppSchema;
|
|
30
|
+
columns: Field[];
|
|
31
|
+
description?: string;
|
|
32
|
+
}): EntitySchema {
|
|
33
|
+
if (options.app && !options.api.apps.includes(options.app)) {
|
|
34
|
+
throw new Error(`entity ${options.name}: api '${options.api.name}' does not serve app '${options.app.name}'`);
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
type: 'entity',
|
|
38
|
+
name: options.name,
|
|
39
|
+
description: options.description,
|
|
40
|
+
api: options.api,
|
|
41
|
+
app: options.app,
|
|
42
|
+
columns: options.columns,
|
|
43
|
+
};
|
|
43
44
|
}
|
package/src/expr.ts
CHANGED
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
// Value expression model: the single declarative way to express computed
|
|
2
|
-
// values in dao methods — update SET expressions and criteria right sides.
|
|
3
|
-
// Structural AST (never SQL strings): column references are Field objects
|
|
4
|
-
// (definition-time ownership checks), values bind as parameters at render
|
|
5
|
-
// time. New node kinds can be added without touching existing declarations.
|
|
6
|
-
|
|
7
|
-
import type { Field } from './dsl.js';
|
|
8
|
-
|
|
9
|
-
/** Binary operator on numeric values. */
|
|
10
|
-
export type BinOp = 'add' | 'sub' | 'mul' | 'div';
|
|
11
|
-
|
|
12
|
-
/** A value expression: column reference / literal / method parameter / binary
|
|
13
|
-
* operation. Recursive — leaves are col/lit/param, bin combines them. */
|
|
14
|
-
export type ValueExpr =
|
|
15
|
-
| { kind: 'col'; field: Field }
|
|
16
|
-
| { kind: 'lit'; value: string | number }
|
|
17
|
-
| { kind: 'param'; name: string }
|
|
18
|
-
| { kind: 'bin'; op: BinOp; left: ValueExpr; right: ValueExpr };
|
|
19
|
-
|
|
20
|
-
/** An update SET assignment: `col = expr` (besides the direct-assignment
|
|
21
|
-
* columns carried by the args entity — a column must not appear in both). */
|
|
22
|
-
export interface SetExpr {
|
|
23
|
-
col: Field;
|
|
24
|
-
expr: ValueExpr;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function col(field: Field): ValueExpr {
|
|
28
|
-
return { kind: 'col', field };
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function lit(value: string | number): ValueExpr {
|
|
32
|
-
return { kind: 'lit', value };
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function param(name: string): ValueExpr {
|
|
36
|
-
return { kind: 'param', name };
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function bin(op: BinOp, left: ValueExpr, right: ValueExpr): ValueExpr {
|
|
40
|
-
return { kind: 'bin', op, left, right };
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** Convenience builders for the common self-increment/decrement shapes. */
|
|
44
|
-
export const incr = (field: Field, by: ValueExpr): SetExpr => ({ col: field, expr: bin('add', col(field), by) });
|
|
45
|
-
export const decr = (field: Field, by: ValueExpr): SetExpr => ({ col: field, expr: bin('sub', col(field), by) });
|
|
46
|
-
|
|
47
|
-
/** Aggregate expression result of an aggregate query column. */
|
|
48
|
-
export interface ComputeExpr {
|
|
49
|
-
fn: 'sum' | 'avg' | 'count';
|
|
50
|
-
/** Column the function applies to; absent for count(*). */
|
|
51
|
-
field?: Field;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/** Aggregate expressions: Compute.sum(col) / Compute.avg(col) / Compute.count(). */
|
|
55
|
-
export const Compute = {
|
|
56
|
-
sum(field: Field): ComputeExpr {
|
|
57
|
-
return { fn: 'sum', field };
|
|
58
|
-
},
|
|
59
|
-
avg(field: Field): ComputeExpr {
|
|
60
|
-
return { fn: 'avg', field };
|
|
61
|
-
},
|
|
62
|
-
count(): ComputeExpr {
|
|
63
|
-
return { fn: 'count' };
|
|
64
|
-
},
|
|
1
|
+
// Value expression model: the single declarative way to express computed
|
|
2
|
+
// values in dao methods — update SET expressions and criteria right sides.
|
|
3
|
+
// Structural AST (never SQL strings): column references are Field objects
|
|
4
|
+
// (definition-time ownership checks), values bind as parameters at render
|
|
5
|
+
// time. New node kinds can be added without touching existing declarations.
|
|
6
|
+
|
|
7
|
+
import type { Field } from './dsl.js';
|
|
8
|
+
|
|
9
|
+
/** Binary operator on numeric values. */
|
|
10
|
+
export type BinOp = 'add' | 'sub' | 'mul' | 'div';
|
|
11
|
+
|
|
12
|
+
/** A value expression: column reference / literal / method parameter / binary
|
|
13
|
+
* operation. Recursive — leaves are col/lit/param, bin combines them. */
|
|
14
|
+
export type ValueExpr =
|
|
15
|
+
| { kind: 'col'; field: Field }
|
|
16
|
+
| { kind: 'lit'; value: string | number }
|
|
17
|
+
| { kind: 'param'; name: string }
|
|
18
|
+
| { kind: 'bin'; op: BinOp; left: ValueExpr; right: ValueExpr };
|
|
19
|
+
|
|
20
|
+
/** An update SET assignment: `col = expr` (besides the direct-assignment
|
|
21
|
+
* columns carried by the args entity — a column must not appear in both). */
|
|
22
|
+
export interface SetExpr {
|
|
23
|
+
col: Field;
|
|
24
|
+
expr: ValueExpr;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function col(field: Field): ValueExpr {
|
|
28
|
+
return { kind: 'col', field };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function lit(value: string | number): ValueExpr {
|
|
32
|
+
return { kind: 'lit', value };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function param(name: string): ValueExpr {
|
|
36
|
+
return { kind: 'param', name };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function bin(op: BinOp, left: ValueExpr, right: ValueExpr): ValueExpr {
|
|
40
|
+
return { kind: 'bin', op, left, right };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Convenience builders for the common self-increment/decrement shapes. */
|
|
44
|
+
export const incr = (field: Field, by: ValueExpr): SetExpr => ({ col: field, expr: bin('add', col(field), by) });
|
|
45
|
+
export const decr = (field: Field, by: ValueExpr): SetExpr => ({ col: field, expr: bin('sub', col(field), by) });
|
|
46
|
+
|
|
47
|
+
/** Aggregate expression result of an aggregate query column. */
|
|
48
|
+
export interface ComputeExpr {
|
|
49
|
+
fn: 'sum' | 'avg' | 'count';
|
|
50
|
+
/** Column the function applies to; absent for count(*). */
|
|
51
|
+
field?: Field;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Aggregate expressions: Compute.sum(col) / Compute.avg(col) / Compute.count(). */
|
|
55
|
+
export const Compute = {
|
|
56
|
+
sum(field: Field): ComputeExpr {
|
|
57
|
+
return { fn: 'sum', field };
|
|
58
|
+
},
|
|
59
|
+
avg(field: Field): ComputeExpr {
|
|
60
|
+
return { fn: 'avg', field };
|
|
61
|
+
},
|
|
62
|
+
count(): ComputeExpr {
|
|
63
|
+
return { fn: 'count' };
|
|
64
|
+
},
|
|
65
65
|
};
|
package/src/filter.ts
CHANGED
|
@@ -1,70 +1,72 @@
|
|
|
1
|
-
import type { Field, Operator, SchemaBase } from './dsl.js';
|
|
2
|
-
import type { ValueExpr } from './expr.js';
|
|
3
|
-
import type { FrontAppSchema, ProjectApiSchema } from './project.js';
|
|
4
|
-
|
|
5
|
-
// Filter: the single declarative model for query conditions, shared by
|
|
6
|
-
// dao_schema methods and curd page lists. Conditions are AND-combined and
|
|
7
|
-
// may reference any table (cross-table filters render JOINs at the usage
|
|
8
|
-
// site, which owns the main table). Pagination is NOT part of a filter —
|
|
9
|
-
// it stays on the dao method (mode) and the curd list config.
|
|
10
|
-
|
|
11
|
-
/** One AND-combined criterion: a column plus its comparison operator. */
|
|
12
|
-
export interface FilterCondition {
|
|
13
|
-
/** Column to compare (any table — cross-table filters are allowed). */
|
|
14
|
-
field: Field;
|
|
15
|
-
/** Comparison operator; defaults to 'eq'. */
|
|
16
|
-
op?: Operator;
|
|
17
|
-
/** Right side of the comparison. Absent = the args parameter named after
|
|
18
|
-
* the column (existing semantics); present = an explicit value expression
|
|
19
|
-
* (column-vs-column, literal, computation). */
|
|
20
|
-
right?: ValueExpr;
|
|
21
|
-
/** Required (default) or optional criterion. A filter has one semantics:
|
|
22
|
-
* dao filters are required (missing criteria = error), page filters are
|
|
23
|
-
* optional (missing criteria = no WHERE). Declared by the filter author. */
|
|
24
|
-
optional?: boolean;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** Query filter: AND-combined conditions plus an optional keyword search. */
|
|
28
|
-
export interface FilterSchema extends SchemaBase {
|
|
29
|
-
type: 'filter';
|
|
30
|
-
/** The backend api module this filter belongs to (shared instance from
|
|
31
|
-
* project.config.ts apis). Filters are backend-side, so storage is
|
|
32
|
-
* filter_schema/{api.name}/{app.name}/filter
|
|
33
|
-
api
|
|
34
|
-
|
|
35
|
-
app
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
|
|
40
|
-
keyword
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
1
|
+
import type { Field, Operator, SchemaBase } from './dsl.js';
|
|
2
|
+
import type { ValueExpr } from './expr.js';
|
|
3
|
+
import type { FrontAppSchema, ProjectApiSchema } from './project.js';
|
|
4
|
+
|
|
5
|
+
// Filter: the single declarative model for query conditions, shared by
|
|
6
|
+
// dao_schema methods and curd page lists. Conditions are AND-combined and
|
|
7
|
+
// may reference any table (cross-table filters render JOINs at the usage
|
|
8
|
+
// site, which owns the main table). Pagination is NOT part of a filter —
|
|
9
|
+
// it stays on the dao method (mode) and the curd list config.
|
|
10
|
+
|
|
11
|
+
/** One AND-combined criterion: a column plus its comparison operator. */
|
|
12
|
+
export interface FilterCondition {
|
|
13
|
+
/** Column to compare (any table — cross-table filters are allowed). */
|
|
14
|
+
field: Field;
|
|
15
|
+
/** Comparison operator; defaults to 'eq'. */
|
|
16
|
+
op?: Operator;
|
|
17
|
+
/** Right side of the comparison. Absent = the args parameter named after
|
|
18
|
+
* the column (existing semantics); present = an explicit value expression
|
|
19
|
+
* (column-vs-column, literal, computation). */
|
|
20
|
+
right?: ValueExpr;
|
|
21
|
+
/** Required (default) or optional criterion. A filter has one semantics:
|
|
22
|
+
* dao filters are required (missing criteria = error), page filters are
|
|
23
|
+
* optional (missing criteria = no WHERE). Declared by the filter author. */
|
|
24
|
+
optional?: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Query filter: AND-combined conditions plus an optional keyword search. */
|
|
28
|
+
export interface FilterSchema extends SchemaBase {
|
|
29
|
+
type: 'filter';
|
|
30
|
+
/** The backend api module this filter belongs to (shared instance from
|
|
31
|
+
* project.config.ts apis). Filters are backend-side, so storage is
|
|
32
|
+
* filter_schema/{api.name}/{app.name}/filter/ — app unset = the api-level
|
|
33
|
+
* common domain layer, stored at filter_schema/{api.name}/common/filter/. */
|
|
34
|
+
api: ProjectApiSchema;
|
|
35
|
+
/** The frontend app this filter belongs to (shared instance from project.config).
|
|
36
|
+
* Unset = api-level common domain filter shared by all modules of the api. */
|
|
37
|
+
app?: FrontAppSchema;
|
|
38
|
+
/** AND-combined conditions (may be empty when keyword is present). */
|
|
39
|
+
conditions: FilterCondition[];
|
|
40
|
+
/** Fuzzy keyword search: one input value matched against multiple columns
|
|
41
|
+
* via OR-like. Presence drives the keyword query endpoint. */
|
|
42
|
+
keyword?: { columns: Field[] };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function defineFilter(options: {
|
|
46
|
+
name: string;
|
|
47
|
+
api: ProjectApiSchema;
|
|
48
|
+
app?: FrontAppSchema;
|
|
49
|
+
conditions?: FilterCondition[];
|
|
50
|
+
keyword?: { columns: Field[] };
|
|
51
|
+
description?: string;
|
|
52
|
+
}): FilterSchema {
|
|
53
|
+
if (options.app && !options.api.apps.includes(options.app)) {
|
|
54
|
+
throw new Error(`filter ${options.name}: api '${options.api.name}' does not serve app '${options.app.name}'`);
|
|
55
|
+
}
|
|
56
|
+
const conditions = options.conditions ?? [];
|
|
57
|
+
if (conditions.length === 0 && options.keyword === undefined) {
|
|
58
|
+
throw new Error(`filter ${options.name}: conditions and keyword cannot both be empty`);
|
|
59
|
+
}
|
|
60
|
+
if (options.keyword !== undefined && options.keyword.columns.length === 0) {
|
|
61
|
+
throw new Error(`filter ${options.name}: keyword columns must be non-empty`);
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
type: 'filter',
|
|
65
|
+
name: options.name,
|
|
66
|
+
description: options.description,
|
|
67
|
+
api: options.api,
|
|
68
|
+
app: options.app,
|
|
69
|
+
conditions,
|
|
70
|
+
keyword: options.keyword,
|
|
71
|
+
};
|
|
70
72
|
}
|