@objectql/core 1.0.0 → 1.2.0
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/CHANGELOG.md +8 -3
- package/dist/index.d.ts +19 -11
- package/dist/index.js +237 -68
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +24 -1
- package/dist/loader.js +152 -146
- package/dist/loader.js.map +1 -1
- package/dist/repository.d.ts +3 -5
- package/dist/repository.js +107 -112
- package/dist/repository.js.map +1 -1
- package/jest.config.js +3 -0
- package/package.json +10 -6
- package/src/index.ts +283 -53
- package/src/loader.ts +178 -166
- package/src/repository.ts +123 -127
- package/test/action.test.ts +58 -0
- package/test/hook.test.ts +60 -0
- package/test/utils.ts +54 -0
- package/tsconfig.json +4 -3
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/driver.d.ts +0 -17
- package/dist/driver.js +0 -3
- package/dist/driver.js.map +0 -1
- package/dist/metadata.d.ts +0 -104
- package/dist/metadata.js +0 -3
- package/dist/metadata.js.map +0 -1
- package/dist/query.d.ts +0 -10
- package/dist/query.js +0 -3
- package/dist/query.js.map +0 -1
- package/dist/types.d.ts +0 -77
- package/dist/types.js +0 -3
- package/dist/types.js.map +0 -1
- package/src/driver.ts +0 -24
- package/src/metadata.ts +0 -143
- package/src/query.ts +0 -11
- package/src/types.ts +0 -109
- package/test/fixtures/project.action.ts +0 -6
- package/test/fixtures/project.object.yml +0 -41
- package/test/loader.test.ts +0 -22
- package/test/metadata.test.ts +0 -49
- package/test/mock-driver.ts +0 -86
- package/test/repository.test.ts +0 -150
package/dist/metadata.d.ts
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Represents the supported field data types in the ObjectQL schema.
|
|
3
|
-
* These types determine how data is stored, validated, and rendered.
|
|
4
|
-
*
|
|
5
|
-
* - `text`: Simple string.
|
|
6
|
-
* - `textarea`: Long string.
|
|
7
|
-
* - `select`: Choice from a list.
|
|
8
|
-
* - `lookup`: Relationship to another object.
|
|
9
|
-
*/
|
|
10
|
-
export type FieldType = 'text' | 'textarea' | 'html' | 'select' | 'multiselect' | 'date' | 'datetime' | 'number' | 'currency' | 'boolean' | 'lookup' | 'master_detail' | 'password' | 'object' | 'grid';
|
|
11
|
-
/**
|
|
12
|
-
* Defines a single option for select/multiselect fields.
|
|
13
|
-
*/
|
|
14
|
-
export interface FieldOption {
|
|
15
|
-
/** The display label for the option. */
|
|
16
|
-
label: string;
|
|
17
|
-
/** The actual value stored in the database. */
|
|
18
|
-
value: string | number;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Configuration for a single field on an object.
|
|
22
|
-
* This defines the schema, validation rules, and UI hints for the attribute.
|
|
23
|
-
*/
|
|
24
|
-
export interface FieldConfig {
|
|
25
|
-
/**
|
|
26
|
-
* The unique API name of the field.
|
|
27
|
-
* If defined within an object map, this is often automatically populated from the key.
|
|
28
|
-
*/
|
|
29
|
-
name?: string;
|
|
30
|
-
/** The human-readable label used in UIs. */
|
|
31
|
-
label?: string;
|
|
32
|
-
/** The data type of the field. */
|
|
33
|
-
type: FieldType;
|
|
34
|
-
/** Whether the field is mandatory. Defaults to false. */
|
|
35
|
-
required?: boolean;
|
|
36
|
-
/** The default value if not provided during creation. */
|
|
37
|
-
defaultValue?: any;
|
|
38
|
-
/**
|
|
39
|
-
* Options available for `select` or `multiselect` types.
|
|
40
|
-
* Can be an array of strings or {@link FieldOption} objects.
|
|
41
|
-
*/
|
|
42
|
-
options?: FieldOption[] | string[];
|
|
43
|
-
/** Number of decimal places for `currency` types (e.g., 2). */
|
|
44
|
-
scale?: number;
|
|
45
|
-
/** Total number of digits for `number` types. */
|
|
46
|
-
precision?: number;
|
|
47
|
-
/**
|
|
48
|
-
* The API name of the target object.
|
|
49
|
-
* Required when type is `lookup` or `master_detail`.
|
|
50
|
-
*/
|
|
51
|
-
reference_to?: string;
|
|
52
|
-
/** Implementation hint: Whether this field should be indexed for search. */
|
|
53
|
-
searchable?: boolean;
|
|
54
|
-
/** Implementation hint: Whether this field is sortable in lists. */
|
|
55
|
-
sortable?: boolean;
|
|
56
|
-
/** Implementation hint: Whether to create a database index for this column. */
|
|
57
|
-
index?: boolean;
|
|
58
|
-
/** Description for documentation purposes. */
|
|
59
|
-
description?: string;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Configuration for a custom action (RPC).
|
|
63
|
-
*/
|
|
64
|
-
export interface ActionConfig {
|
|
65
|
-
label?: string;
|
|
66
|
-
description?: string;
|
|
67
|
-
/** Output/Result type definition. */
|
|
68
|
-
result?: {
|
|
69
|
-
type: FieldType;
|
|
70
|
-
};
|
|
71
|
-
/** Input parameters schema. */
|
|
72
|
-
params?: Record<string, FieldConfig>;
|
|
73
|
-
/** Implementation of the action. */
|
|
74
|
-
handler?: (ctx: any, params: any) => Promise<any>;
|
|
75
|
-
}
|
|
76
|
-
import { HookFunction } from './types';
|
|
77
|
-
export interface ObjectListeners {
|
|
78
|
-
beforeCreate?: HookFunction;
|
|
79
|
-
afterCreate?: HookFunction;
|
|
80
|
-
beforeUpdate?: HookFunction;
|
|
81
|
-
afterUpdate?: HookFunction;
|
|
82
|
-
beforeDelete?: HookFunction;
|
|
83
|
-
afterDelete?: HookFunction;
|
|
84
|
-
beforeFind?: HookFunction;
|
|
85
|
-
afterFind?: HookFunction;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Configuration for a business object (Entity).
|
|
89
|
-
* Analogous to a Database Table or MongoDB Collection.
|
|
90
|
-
*/
|
|
91
|
-
export interface ObjectConfig {
|
|
92
|
-
name: string;
|
|
93
|
-
datasource?: string;
|
|
94
|
-
label?: string;
|
|
95
|
-
icon?: string;
|
|
96
|
-
description?: string;
|
|
97
|
-
fields: Record<string, FieldConfig>;
|
|
98
|
-
/** Custom Actions (RPC) defined on this object. */
|
|
99
|
-
actions?: Record<string, ActionConfig>;
|
|
100
|
-
/** Lifecycle hooks. */
|
|
101
|
-
listeners?: ObjectListeners;
|
|
102
|
-
/** Initial data to populate when system starts. */
|
|
103
|
-
data?: any[];
|
|
104
|
-
}
|
package/dist/metadata.js
DELETED
package/dist/metadata.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":""}
|
package/dist/query.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export type FilterCriterion = [string, string, any];
|
|
2
|
-
export type FilterExpression = FilterCriterion | 'and' | 'or' | FilterExpression[];
|
|
3
|
-
export interface UnifiedQuery {
|
|
4
|
-
fields?: string[];
|
|
5
|
-
filters?: FilterExpression[];
|
|
6
|
-
sort?: [string, 'asc' | 'desc'][];
|
|
7
|
-
skip?: number;
|
|
8
|
-
limit?: number;
|
|
9
|
-
expand?: Record<string, UnifiedQuery>;
|
|
10
|
-
}
|
package/dist/query.js
DELETED
package/dist/query.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":""}
|
package/dist/types.d.ts
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { ObjectRepository } from "./repository";
|
|
2
|
-
import { ObjectConfig } from "./metadata";
|
|
3
|
-
import { Driver } from "./driver";
|
|
4
|
-
import { UnifiedQuery, FilterCriterion } from "./query";
|
|
5
|
-
export { ObjectConfig } from "./metadata";
|
|
6
|
-
export interface ObjectQLConfig {
|
|
7
|
-
datasources: Record<string, Driver>;
|
|
8
|
-
objects?: Record<string, ObjectConfig>;
|
|
9
|
-
packages?: string[];
|
|
10
|
-
}
|
|
11
|
-
export interface IObjectQL {
|
|
12
|
-
getObject(name: string): ObjectConfig | undefined;
|
|
13
|
-
getConfigs(): Record<string, ObjectConfig>;
|
|
14
|
-
datasource(name: string): Driver;
|
|
15
|
-
init(): Promise<void>;
|
|
16
|
-
}
|
|
17
|
-
export interface HookContext<T = any> {
|
|
18
|
-
ctx: ObjectQLContext;
|
|
19
|
-
entity: string;
|
|
20
|
-
op: 'find' | 'create' | 'update' | 'delete' | 'count' | 'aggregate';
|
|
21
|
-
doc?: T;
|
|
22
|
-
query?: UnifiedQuery;
|
|
23
|
-
getPreviousDoc: () => Promise<T | undefined>;
|
|
24
|
-
utils: {
|
|
25
|
-
/**
|
|
26
|
-
* Safely injects a new filter criterion into the existing AST.
|
|
27
|
-
* It wraps existing filters in a new group to preserve operator precedence.
|
|
28
|
-
* * Logic: (Existing_Filters) AND (New_Filter)
|
|
29
|
-
*/
|
|
30
|
-
restrict: (criterion: FilterCriterion) => void;
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
export type HookFunction = (context: HookContext) => Promise<void>;
|
|
34
|
-
export interface ObjectQLContext {
|
|
35
|
-
userId?: string;
|
|
36
|
-
spaceId?: string;
|
|
37
|
-
roles: string[];
|
|
38
|
-
/**
|
|
39
|
-
* Sudo Mode / System Bypass.
|
|
40
|
-
* - true: Bypasses all permission checks (CRUD, Field Level Security, Record Level Security).
|
|
41
|
-
* - false/undefined: Enforces all permission checks based on 'roles'.
|
|
42
|
-
*/
|
|
43
|
-
isSystem?: boolean;
|
|
44
|
-
/**
|
|
45
|
-
* Trigger Control.
|
|
46
|
-
* - true: Skips all lifecycle hooks (beforeCreate, afterUpdate, etc.).
|
|
47
|
-
* - Useful for bulk data imports or raw data correction to prevent side effects.
|
|
48
|
-
* - Requires 'isSystem: true' (Security Safeguard).
|
|
49
|
-
*/
|
|
50
|
-
ignoreTriggers?: boolean;
|
|
51
|
-
/**
|
|
52
|
-
* Returns a repository proxy bound to this context.
|
|
53
|
-
* All operations performed via this proxy inherit userId, spaceId, and transaction.
|
|
54
|
-
*/
|
|
55
|
-
object(entityName: string): ObjectRepository;
|
|
56
|
-
/**
|
|
57
|
-
* Execute a function within a transaction.
|
|
58
|
-
* The callback receives a new context 'trxCtx' which inherits userId and spaceId from this context.
|
|
59
|
-
*/
|
|
60
|
-
transaction(callback: (trxCtx: ObjectQLContext) => Promise<any>): Promise<any>;
|
|
61
|
-
/**
|
|
62
|
-
* Returns a new context with system privileges (isSystem: true).
|
|
63
|
-
* It shares the same transaction scope as the current context.
|
|
64
|
-
*/
|
|
65
|
-
sudo(): ObjectQLContext;
|
|
66
|
-
/**
|
|
67
|
-
* Internal: Driver-specific transaction handle.
|
|
68
|
-
*/
|
|
69
|
-
transactionHandle?: any;
|
|
70
|
-
}
|
|
71
|
-
export interface ObjectQLContextOptions {
|
|
72
|
-
userId?: string;
|
|
73
|
-
spaceId?: string;
|
|
74
|
-
roles?: string[];
|
|
75
|
-
isSystem?: boolean;
|
|
76
|
-
ignoreTriggers?: boolean;
|
|
77
|
-
}
|
package/dist/types.js
DELETED
package/dist/types.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/src/driver.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export interface Driver {
|
|
2
|
-
find(objectName: string, query: any, options?: any): Promise<any[]>;
|
|
3
|
-
findOne(objectName: string, id: string | number, query?: any, options?: any): Promise<any>;
|
|
4
|
-
create(objectName: string, data: any, options?: any): Promise<any>;
|
|
5
|
-
update(objectName: string, id: string | number, data: any, options?: any): Promise<any>;
|
|
6
|
-
delete(objectName: string, id: string | number, options?: any): Promise<any>;
|
|
7
|
-
count(objectName: string, filters: any, options?: any): Promise<number>;
|
|
8
|
-
|
|
9
|
-
// Advanced
|
|
10
|
-
aggregate?(objectName: string, query: any, options?: any): Promise<any>;
|
|
11
|
-
distinct?(objectName: string, field: string, filters?: any, options?: any): Promise<any[]>;
|
|
12
|
-
|
|
13
|
-
// Bulk / Atomic
|
|
14
|
-
createMany?(objectName: string, data: any[], options?: any): Promise<any>;
|
|
15
|
-
updateMany?(objectName: string, filters: any, data: any, options?: any): Promise<any>;
|
|
16
|
-
deleteMany?(objectName: string, filters: any, options?: any): Promise<any>;
|
|
17
|
-
findOneAndUpdate?(objectName: string, filters: any, update: any, options?: any): Promise<any>;
|
|
18
|
-
|
|
19
|
-
// Transaction
|
|
20
|
-
beginTransaction?(): Promise<any>;
|
|
21
|
-
commitTransaction?(trx: any): Promise<void>;
|
|
22
|
-
rollbackTransaction?(trx: any): Promise<void>;
|
|
23
|
-
}
|
|
24
|
-
|
package/src/metadata.ts
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Represents the supported field data types in the ObjectQL schema.
|
|
3
|
-
* These types determine how data is stored, validated, and rendered.
|
|
4
|
-
*
|
|
5
|
-
* - `text`: Simple string.
|
|
6
|
-
* - `textarea`: Long string.
|
|
7
|
-
* - `select`: Choice from a list.
|
|
8
|
-
* - `lookup`: Relationship to another object.
|
|
9
|
-
*/
|
|
10
|
-
export type FieldType =
|
|
11
|
-
| 'text'
|
|
12
|
-
| 'textarea'
|
|
13
|
-
| 'html'
|
|
14
|
-
| 'select'
|
|
15
|
-
| 'multiselect'
|
|
16
|
-
| 'date'
|
|
17
|
-
| 'datetime'
|
|
18
|
-
| 'number'
|
|
19
|
-
| 'currency'
|
|
20
|
-
| 'boolean'
|
|
21
|
-
| 'lookup'
|
|
22
|
-
| 'master_detail'
|
|
23
|
-
| 'password'
|
|
24
|
-
| 'object'
|
|
25
|
-
| 'grid';
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Defines a single option for select/multiselect fields.
|
|
29
|
-
*/
|
|
30
|
-
export interface FieldOption {
|
|
31
|
-
/** The display label for the option. */
|
|
32
|
-
label: string;
|
|
33
|
-
/** The actual value stored in the database. */
|
|
34
|
-
value: string | number;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Configuration for a single field on an object.
|
|
39
|
-
* This defines the schema, validation rules, and UI hints for the attribute.
|
|
40
|
-
*/
|
|
41
|
-
export interface FieldConfig {
|
|
42
|
-
/**
|
|
43
|
-
* The unique API name of the field.
|
|
44
|
-
* If defined within an object map, this is often automatically populated from the key.
|
|
45
|
-
*/
|
|
46
|
-
name?: string;
|
|
47
|
-
|
|
48
|
-
/** The human-readable label used in UIs. */
|
|
49
|
-
label?: string;
|
|
50
|
-
|
|
51
|
-
/** The data type of the field. */
|
|
52
|
-
type: FieldType;
|
|
53
|
-
|
|
54
|
-
/** Whether the field is mandatory. Defaults to false. */
|
|
55
|
-
required?: boolean;
|
|
56
|
-
|
|
57
|
-
/** The default value if not provided during creation. */
|
|
58
|
-
defaultValue?: any;
|
|
59
|
-
|
|
60
|
-
// String options
|
|
61
|
-
/**
|
|
62
|
-
* Options available for `select` or `multiselect` types.
|
|
63
|
-
* Can be an array of strings or {@link FieldOption} objects.
|
|
64
|
-
*/
|
|
65
|
-
options?: FieldOption[] | string[];
|
|
66
|
-
|
|
67
|
-
// Number options
|
|
68
|
-
/** Number of decimal places for `currency` types (e.g., 2). */
|
|
69
|
-
scale?: number;
|
|
70
|
-
/** Total number of digits for `number` types. */
|
|
71
|
-
precision?: number;
|
|
72
|
-
|
|
73
|
-
// Relationship properties
|
|
74
|
-
/**
|
|
75
|
-
* The API name of the target object.
|
|
76
|
-
* Required when type is `lookup` or `master_detail`.
|
|
77
|
-
*/
|
|
78
|
-
reference_to?: string;
|
|
79
|
-
|
|
80
|
-
// UI properties (kept for compatibility, though ObjectQL is a query engine)
|
|
81
|
-
/** Implementation hint: Whether this field should be indexed for search. */
|
|
82
|
-
searchable?: boolean;
|
|
83
|
-
/** Implementation hint: Whether this field is sortable in lists. */
|
|
84
|
-
sortable?: boolean;
|
|
85
|
-
/** Implementation hint: Whether to create a database index for this column. */
|
|
86
|
-
index?: boolean;
|
|
87
|
-
|
|
88
|
-
// Other properties
|
|
89
|
-
/** Description for documentation purposes. */
|
|
90
|
-
description?: string;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Configuration for a custom action (RPC).
|
|
95
|
-
*/
|
|
96
|
-
export interface ActionConfig {
|
|
97
|
-
label?: string;
|
|
98
|
-
description?: string;
|
|
99
|
-
/** Output/Result type definition. */
|
|
100
|
-
result?: {
|
|
101
|
-
type: FieldType;
|
|
102
|
-
};
|
|
103
|
-
/** Input parameters schema. */
|
|
104
|
-
params?: Record<string, FieldConfig>;
|
|
105
|
-
/** Implementation of the action. */
|
|
106
|
-
handler?: (ctx: any, params: any) => Promise<any>;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
import { HookFunction } from './types';
|
|
110
|
-
|
|
111
|
-
export interface ObjectListeners {
|
|
112
|
-
beforeCreate?: HookFunction;
|
|
113
|
-
afterCreate?: HookFunction;
|
|
114
|
-
beforeUpdate?: HookFunction;
|
|
115
|
-
afterUpdate?: HookFunction;
|
|
116
|
-
beforeDelete?: HookFunction;
|
|
117
|
-
afterDelete?: HookFunction;
|
|
118
|
-
beforeFind?: HookFunction;
|
|
119
|
-
afterFind?: HookFunction;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Configuration for a business object (Entity).
|
|
124
|
-
* Analogous to a Database Table or MongoDB Collection.
|
|
125
|
-
*/
|
|
126
|
-
export interface ObjectConfig {
|
|
127
|
-
name: string;
|
|
128
|
-
datasource?: string; // The name of the datasource to use
|
|
129
|
-
label?: string;
|
|
130
|
-
icon?: string;
|
|
131
|
-
description?: string;
|
|
132
|
-
|
|
133
|
-
fields: Record<string, FieldConfig>;
|
|
134
|
-
|
|
135
|
-
/** Custom Actions (RPC) defined on this object. */
|
|
136
|
-
actions?: Record<string, ActionConfig>;
|
|
137
|
-
|
|
138
|
-
/** Lifecycle hooks. */
|
|
139
|
-
listeners?: ObjectListeners;
|
|
140
|
-
|
|
141
|
-
/** Initial data to populate when system starts. */
|
|
142
|
-
data?: any[];
|
|
143
|
-
}
|
package/src/query.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export type FilterCriterion = [string, string, any];
|
|
2
|
-
export type FilterExpression = FilterCriterion | 'and' | 'or' | FilterExpression[];
|
|
3
|
-
|
|
4
|
-
export interface UnifiedQuery {
|
|
5
|
-
fields?: string[];
|
|
6
|
-
filters?: FilterExpression[];
|
|
7
|
-
sort?: [string, 'asc' | 'desc'][];
|
|
8
|
-
skip?: number;
|
|
9
|
-
limit?: number;
|
|
10
|
-
expand?: Record<string, UnifiedQuery>;
|
|
11
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { ObjectRepository } from "./repository";
|
|
2
|
-
import { ObjectConfig } from "./metadata";
|
|
3
|
-
import { Driver } from "./driver";
|
|
4
|
-
import { UnifiedQuery, FilterCriterion } from "./query";
|
|
5
|
-
|
|
6
|
-
export { ObjectConfig } from "./metadata";
|
|
7
|
-
|
|
8
|
-
export interface ObjectQLConfig {
|
|
9
|
-
datasources: Record<string, Driver>;
|
|
10
|
-
objects?: Record<string, ObjectConfig>;
|
|
11
|
-
packages?: string[];
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface IObjectQL {
|
|
15
|
-
getObject(name: string): ObjectConfig | undefined;
|
|
16
|
-
getConfigs(): Record<string, ObjectConfig>;
|
|
17
|
-
datasource(name: string): Driver;
|
|
18
|
-
init(): Promise<void>;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface HookContext<T = any> {
|
|
22
|
-
// === 1. The Session Context ===
|
|
23
|
-
// Automatically propagates userId, spaceId, and Transaction.
|
|
24
|
-
ctx: ObjectQLContext;
|
|
25
|
-
|
|
26
|
-
// === 2. Operational Info ===
|
|
27
|
-
entity: string;
|
|
28
|
-
op: 'find' | 'create' | 'update' | 'delete' | 'count' | 'aggregate';
|
|
29
|
-
|
|
30
|
-
// === 3. Data Payload (Mutable) ===
|
|
31
|
-
// - In beforeCreate/Update: The data to be written.
|
|
32
|
-
// - In afterCreate/Update: The result record returned from DB.
|
|
33
|
-
doc?: T;
|
|
34
|
-
|
|
35
|
-
// === 4. Query Context (Mutable, for 'find' only) ===
|
|
36
|
-
// Complies strictly with the UnifiedQuery JSON-DSL (AST).
|
|
37
|
-
// Developers can modify 'fields', 'sort', or wrap 'filters'.
|
|
38
|
-
query?: UnifiedQuery;
|
|
39
|
-
|
|
40
|
-
// === 5. Helpers ===
|
|
41
|
-
getPreviousDoc: () => Promise<T | undefined>;
|
|
42
|
-
|
|
43
|
-
// AST Manipulation Utilities
|
|
44
|
-
utils: {
|
|
45
|
-
/**
|
|
46
|
-
* Safely injects a new filter criterion into the existing AST.
|
|
47
|
-
* It wraps existing filters in a new group to preserve operator precedence.
|
|
48
|
-
* * Logic: (Existing_Filters) AND (New_Filter)
|
|
49
|
-
*/
|
|
50
|
-
restrict: (criterion: FilterCriterion) => void;
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export type HookFunction = (context: HookContext) => Promise<void>;
|
|
55
|
-
|
|
56
|
-
export interface ObjectQLContext {
|
|
57
|
-
// === Identity & Isolation ===
|
|
58
|
-
userId?: string; // Current User ID
|
|
59
|
-
spaceId?: string; // Multi-tenancy Isolation (Organization ID)
|
|
60
|
-
roles: string[]; // RBAC Roles
|
|
61
|
-
|
|
62
|
-
// === Execution Flags ===
|
|
63
|
-
/**
|
|
64
|
-
* Sudo Mode / System Bypass.
|
|
65
|
-
* - true: Bypasses all permission checks (CRUD, Field Level Security, Record Level Security).
|
|
66
|
-
* - false/undefined: Enforces all permission checks based on 'roles'.
|
|
67
|
-
*/
|
|
68
|
-
isSystem?: boolean;
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Trigger Control.
|
|
72
|
-
* - true: Skips all lifecycle hooks (beforeCreate, afterUpdate, etc.).
|
|
73
|
-
* - Useful for bulk data imports or raw data correction to prevent side effects.
|
|
74
|
-
* - Requires 'isSystem: true' (Security Safeguard).
|
|
75
|
-
*/
|
|
76
|
-
ignoreTriggers?: boolean;
|
|
77
|
-
|
|
78
|
-
// === Data Entry Point ===
|
|
79
|
-
/**
|
|
80
|
-
* Returns a repository proxy bound to this context.
|
|
81
|
-
* All operations performed via this proxy inherit userId, spaceId, and transaction.
|
|
82
|
-
*/
|
|
83
|
-
object(entityName: string): ObjectRepository;
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Execute a function within a transaction.
|
|
87
|
-
* The callback receives a new context 'trxCtx' which inherits userId and spaceId from this context.
|
|
88
|
-
*/
|
|
89
|
-
transaction(callback: (trxCtx: ObjectQLContext) => Promise<any>): Promise<any>;
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Returns a new context with system privileges (isSystem: true).
|
|
93
|
-
* It shares the same transaction scope as the current context.
|
|
94
|
-
*/
|
|
95
|
-
sudo(): ObjectQLContext;
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Internal: Driver-specific transaction handle.
|
|
99
|
-
*/
|
|
100
|
-
transactionHandle?: any;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export interface ObjectQLContextOptions {
|
|
104
|
-
userId?: string;
|
|
105
|
-
spaceId?: string;
|
|
106
|
-
roles?: string[];
|
|
107
|
-
isSystem?: boolean;
|
|
108
|
-
ignoreTriggers?: boolean;
|
|
109
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
name: project
|
|
2
|
-
label: Project
|
|
3
|
-
icon: standard:case
|
|
4
|
-
enable_search: true
|
|
5
|
-
fields:
|
|
6
|
-
name:
|
|
7
|
-
label: Project Name
|
|
8
|
-
type: text
|
|
9
|
-
required: true
|
|
10
|
-
searchable: true
|
|
11
|
-
index: true
|
|
12
|
-
|
|
13
|
-
status:
|
|
14
|
-
label: Status
|
|
15
|
-
type: select
|
|
16
|
-
options:
|
|
17
|
-
- label: Planned
|
|
18
|
-
value: planned
|
|
19
|
-
- label: In Progress
|
|
20
|
-
value: in_progress
|
|
21
|
-
- label: Completed
|
|
22
|
-
value: completed
|
|
23
|
-
defaultValue: planned
|
|
24
|
-
|
|
25
|
-
start_date:
|
|
26
|
-
label: Start Date
|
|
27
|
-
type: date
|
|
28
|
-
|
|
29
|
-
owner:
|
|
30
|
-
label: Project Manager
|
|
31
|
-
type: lookup
|
|
32
|
-
reference_to: users
|
|
33
|
-
|
|
34
|
-
budget:
|
|
35
|
-
label: Total Budget
|
|
36
|
-
type: currency
|
|
37
|
-
scale: 2
|
|
38
|
-
|
|
39
|
-
description:
|
|
40
|
-
label: Description
|
|
41
|
-
type: textarea
|
package/test/loader.test.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { loadObjectConfigs } from '../src/loader';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
|
|
4
|
-
describe('Loader', () => {
|
|
5
|
-
it('should load object configs from directory', () => {
|
|
6
|
-
const fixturesDir = path.join(__dirname, 'fixtures');
|
|
7
|
-
const configs = loadObjectConfigs(fixturesDir);
|
|
8
|
-
expect(configs).toBeDefined();
|
|
9
|
-
expect(configs['project']).toBeDefined();
|
|
10
|
-
expect(configs['project'].name).toBe('project');
|
|
11
|
-
expect(configs['project'].fields).toBeDefined();
|
|
12
|
-
expect(configs['project'].fields.name).toBeDefined();
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('should load actions from .action.ts files', () => {
|
|
16
|
-
const fixturesDir = path.join(__dirname, 'fixtures');
|
|
17
|
-
const configs = loadObjectConfigs(fixturesDir);
|
|
18
|
-
expect(configs['project'].actions).toBeDefined();
|
|
19
|
-
expect(configs['project'].actions!.closeProject).toBeDefined();
|
|
20
|
-
expect(typeof configs['project'].actions!.closeProject.handler).toBe('function');
|
|
21
|
-
});
|
|
22
|
-
});
|
package/test/metadata.test.ts
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { ObjectQL } from '../src/index';
|
|
2
|
-
import { ObjectConfig } from '../src/metadata';
|
|
3
|
-
import * as fs from 'fs';
|
|
4
|
-
import * as path from 'path';
|
|
5
|
-
import * as yaml from 'js-yaml';
|
|
6
|
-
|
|
7
|
-
describe('Metadata Loading', () => {
|
|
8
|
-
|
|
9
|
-
it('should load definitions from .object.yml file', () => {
|
|
10
|
-
// 1. Read YAML file
|
|
11
|
-
const yamlPath = path.join(__dirname, 'fixtures', 'project.object.yml');
|
|
12
|
-
const fileContents = fs.readFileSync(yamlPath, 'utf8');
|
|
13
|
-
|
|
14
|
-
// 2. Parse YAML
|
|
15
|
-
const objectDef = yaml.load(fileContents) as ObjectConfig;
|
|
16
|
-
|
|
17
|
-
// 3. Verify Structure
|
|
18
|
-
expect(objectDef.name).toBe('project');
|
|
19
|
-
expect(objectDef.fields.name.type).toBe('text');
|
|
20
|
-
expect(objectDef.fields.status.options).toHaveLength(3);
|
|
21
|
-
expect(objectDef.fields.budget.type).toBe('currency');
|
|
22
|
-
expect(objectDef.fields.owner.reference_to).toBe('users');
|
|
23
|
-
|
|
24
|
-
// 4. Register with ObjectQL
|
|
25
|
-
const app = new ObjectQL({
|
|
26
|
-
datasources: {}
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
app.registerObject(objectDef);
|
|
30
|
-
|
|
31
|
-
// 5. Verify Registration
|
|
32
|
-
const retrieved = app.getObject('project');
|
|
33
|
-
expect(retrieved).toBeDefined();
|
|
34
|
-
expect(retrieved?.label).toBe('Project');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should validate required properties (manual validation simulation)', () => {
|
|
38
|
-
const yamlPath = path.join(__dirname, 'fixtures', 'project.object.yml');
|
|
39
|
-
const fileContents = fs.readFileSync(yamlPath, 'utf8');
|
|
40
|
-
const objectDef = yaml.load(fileContents) as ObjectConfig;
|
|
41
|
-
|
|
42
|
-
function validateObject(obj: ObjectConfig) {
|
|
43
|
-
if (!obj.name) throw new Error('Object name is required');
|
|
44
|
-
if (!obj.fields) throw new Error('Object fields are required');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
expect(() => validateObject(objectDef)).not.toThrow();
|
|
48
|
-
});
|
|
49
|
-
});
|