@objectql/core 0.1.0 → 1.1.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 +18 -0
- package/README.md +53 -0
- package/dist/index.d.ts +9 -2
- package/dist/index.js +56 -12
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +5 -0
- package/dist/loader.js +17 -136
- package/dist/loader.js.map +1 -1
- package/dist/metadata.d.ts +2 -0
- package/dist/registry.d.ts +4 -0
- package/dist/registry.js +8 -0
- package/dist/registry.js.map +1 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -1
- package/package.json +3 -2
- package/src/index.ts +65 -13
- package/src/loader.ts +17 -115
- package/src/metadata.ts +3 -1
- package/src/registry.ts +6 -0
- package/src/types.ts +8 -0
- package/test/dynamic.test.ts +34 -0
- package/test/fixtures/project.action.ts +6 -0
- package/test/loader.test.ts +8 -0
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# @objectql/core
|
|
2
|
+
|
|
3
|
+
The core ORM and runtime engine for ObjectQL. This package handles object querying, CRUD operations, database driver coordination, and transaction management.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Unified Query Language**: A generic way to query data across different databases (SQL, Mongo, etc.).
|
|
8
|
+
- **Repository Pattern**: `ObjectRepository` for managing object records.
|
|
9
|
+
- **Driver Agnostic**: Abstraction layer for database drivers.
|
|
10
|
+
- **Dynamic Schema**: Loads object definitions from `@objectql/metadata`.
|
|
11
|
+
- **Hooks & Actions**: Runtime logic injection.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @objectql/core
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { ObjectQL } from '@objectql/core';
|
|
23
|
+
import { MetadataRegistry } from '@objectql/metadata';
|
|
24
|
+
// Import a driver, e.g., @objectql/driver-knex
|
|
25
|
+
|
|
26
|
+
const objectql = new ObjectQL({
|
|
27
|
+
datasources: {
|
|
28
|
+
default: new MyDriver({ ... })
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
await objectql.init();
|
|
33
|
+
|
|
34
|
+
// Use context for operations
|
|
35
|
+
const ctx = objectql.createContext({ userId: 'u-1' });
|
|
36
|
+
const projects = await ctx.object('project').find({
|
|
37
|
+
filters: [['status', '=', 'active']]
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Shared Metadata
|
|
42
|
+
|
|
43
|
+
You can pass an existing `MetadataRegistry` (e.g., from a low-code platform loader) to ObjectQL:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
const registry = new MetadataRegistry();
|
|
47
|
+
// ... pre-load metadata ...
|
|
48
|
+
|
|
49
|
+
const objectql = new ObjectQL({
|
|
50
|
+
registry: registry,
|
|
51
|
+
datasources: { ... }
|
|
52
|
+
});
|
|
53
|
+
```
|
package/dist/index.d.ts
CHANGED
|
@@ -3,17 +3,24 @@ export * from './types';
|
|
|
3
3
|
export * from './driver';
|
|
4
4
|
export * from './repository';
|
|
5
5
|
export * from './query';
|
|
6
|
+
export * from './registry';
|
|
7
|
+
export * from './loader';
|
|
6
8
|
import { ObjectConfig } from './metadata';
|
|
7
9
|
import { ObjectQLContext, ObjectQLContextOptions, IObjectQL, ObjectQLConfig } from './types';
|
|
8
10
|
import { Driver } from './driver';
|
|
11
|
+
import { MetadataRegistry } from './registry';
|
|
9
12
|
export declare class ObjectQL implements IObjectQL {
|
|
10
|
-
|
|
13
|
+
metadata: MetadataRegistry;
|
|
14
|
+
private loader;
|
|
11
15
|
private datasources;
|
|
12
16
|
constructor(config: ObjectQLConfig);
|
|
13
|
-
|
|
17
|
+
addPackage(name: string): void;
|
|
18
|
+
removePackage(name: string): void;
|
|
19
|
+
loadFromDirectory(dir: string, packageName?: string): void;
|
|
14
20
|
createContext(options: ObjectQLContextOptions): ObjectQLContext;
|
|
15
21
|
registerObject(object: ObjectConfig): void;
|
|
16
22
|
getObject(name: string): ObjectConfig | undefined;
|
|
17
23
|
getConfigs(): Record<string, ObjectConfig>;
|
|
18
24
|
datasource(name: string): Driver;
|
|
25
|
+
init(): Promise<void>;
|
|
19
26
|
}
|
package/dist/index.js
CHANGED
|
@@ -20,25 +20,37 @@ __exportStar(require("./types"), exports);
|
|
|
20
20
|
__exportStar(require("./driver"), exports);
|
|
21
21
|
__exportStar(require("./repository"), exports);
|
|
22
22
|
__exportStar(require("./query"), exports);
|
|
23
|
+
__exportStar(require("./registry"), exports);
|
|
24
|
+
__exportStar(require("./loader"), exports);
|
|
23
25
|
const repository_1 = require("./repository");
|
|
24
26
|
const loader_1 = require("./loader");
|
|
27
|
+
const registry_1 = require("./registry");
|
|
25
28
|
class ObjectQL {
|
|
26
29
|
constructor(config) {
|
|
27
|
-
this.objects = {};
|
|
28
30
|
this.datasources = {};
|
|
31
|
+
this.metadata = config.registry || new registry_1.MetadataRegistry();
|
|
32
|
+
this.loader = new loader_1.MetadataLoader(this.metadata);
|
|
29
33
|
this.datasources = config.datasources;
|
|
30
34
|
if (config.objects) {
|
|
31
|
-
for (const obj of Object.
|
|
35
|
+
for (const [key, obj] of Object.entries(config.objects)) {
|
|
32
36
|
this.registerObject(obj);
|
|
33
37
|
}
|
|
34
38
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
this.registerObject(obj);
|
|
39
|
+
if (config.packages) {
|
|
40
|
+
for (const name of config.packages) {
|
|
41
|
+
this.addPackage(name);
|
|
42
|
+
}
|
|
40
43
|
}
|
|
41
44
|
}
|
|
45
|
+
addPackage(name) {
|
|
46
|
+
this.loader.loadPackage(name);
|
|
47
|
+
}
|
|
48
|
+
removePackage(name) {
|
|
49
|
+
this.metadata.unregisterPackage(name);
|
|
50
|
+
}
|
|
51
|
+
loadFromDirectory(dir, packageName) {
|
|
52
|
+
this.loader.load(dir, packageName);
|
|
53
|
+
}
|
|
42
54
|
createContext(options) {
|
|
43
55
|
const ctx = {
|
|
44
56
|
userId: options.userId,
|
|
@@ -59,13 +71,11 @@ class ObjectQL {
|
|
|
59
71
|
trx = await driver.beginTransaction();
|
|
60
72
|
}
|
|
61
73
|
catch (e) {
|
|
62
|
-
// If beginTransaction fails, fail.
|
|
63
74
|
throw e;
|
|
64
75
|
}
|
|
65
76
|
const trxCtx = {
|
|
66
77
|
...ctx,
|
|
67
78
|
transactionHandle: trx,
|
|
68
|
-
// Nested transaction simply reuses the current one (flat transaction)
|
|
69
79
|
transaction: async (cb) => cb(trxCtx)
|
|
70
80
|
};
|
|
71
81
|
try {
|
|
@@ -95,13 +105,22 @@ class ObjectQL {
|
|
|
95
105
|
}
|
|
96
106
|
}
|
|
97
107
|
}
|
|
98
|
-
this.
|
|
108
|
+
this.metadata.register('object', {
|
|
109
|
+
type: 'object',
|
|
110
|
+
id: object.name,
|
|
111
|
+
content: object
|
|
112
|
+
});
|
|
99
113
|
}
|
|
100
114
|
getObject(name) {
|
|
101
|
-
return this.
|
|
115
|
+
return this.metadata.get('object', name);
|
|
102
116
|
}
|
|
103
117
|
getConfigs() {
|
|
104
|
-
|
|
118
|
+
const result = {};
|
|
119
|
+
const objects = this.metadata.list('object');
|
|
120
|
+
for (const obj of objects) {
|
|
121
|
+
result[obj.name] = obj;
|
|
122
|
+
}
|
|
123
|
+
return result;
|
|
105
124
|
}
|
|
106
125
|
datasource(name) {
|
|
107
126
|
const driver = this.datasources[name];
|
|
@@ -110,6 +129,31 @@ class ObjectQL {
|
|
|
110
129
|
}
|
|
111
130
|
return driver;
|
|
112
131
|
}
|
|
132
|
+
async init() {
|
|
133
|
+
const ctx = this.createContext({ isSystem: true });
|
|
134
|
+
const objects = this.metadata.list('object');
|
|
135
|
+
for (const obj of objects) {
|
|
136
|
+
if (obj.data && obj.data.length > 0) {
|
|
137
|
+
console.log(`Initializing data for object ${obj.name}...`);
|
|
138
|
+
const repo = ctx.object(obj.name);
|
|
139
|
+
for (const record of obj.data) {
|
|
140
|
+
try {
|
|
141
|
+
if (record._id) {
|
|
142
|
+
const existing = await repo.findOne(record._id);
|
|
143
|
+
if (existing) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
await repo.create(record);
|
|
148
|
+
console.log(`Inserted init data for ${obj.name}: ${record._id || 'unknown id'}`);
|
|
149
|
+
}
|
|
150
|
+
catch (e) {
|
|
151
|
+
console.error(`Failed to insert init data for ${obj.name}:`, e);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
113
157
|
}
|
|
114
158
|
exports.ObjectQL = ObjectQL;
|
|
115
159
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/loader.d.ts
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
|
+
import { MetadataRegistry } from './registry';
|
|
1
2
|
import { ObjectConfig } from './types';
|
|
3
|
+
import { MetadataLoader as BaseLoader } from '@objectql/metadata';
|
|
4
|
+
export declare class MetadataLoader extends BaseLoader {
|
|
5
|
+
constructor(registry: MetadataRegistry);
|
|
6
|
+
}
|
|
2
7
|
export declare function loadObjectConfigs(dir: string): Record<string, ObjectConfig>;
|
package/dist/loader.js
CHANGED
|
@@ -1,143 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MetadataLoader = void 0;
|
|
36
4
|
exports.loadObjectConfigs = loadObjectConfigs;
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// 1. Load YAML Configs
|
|
44
|
-
const files = glob.sync(['**/*.object.yml', '**/*.object.yaml'], {
|
|
45
|
-
cwd: dir,
|
|
46
|
-
absolute: true
|
|
47
|
-
});
|
|
48
|
-
for (const file of files) {
|
|
49
|
-
try {
|
|
50
|
-
const content = fs.readFileSync(file, 'utf8');
|
|
51
|
-
const doc = yaml.load(content);
|
|
52
|
-
if (doc.name && doc.fields) {
|
|
53
|
-
configs[doc.name] = doc;
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
for (const [key, value] of Object.entries(doc)) {
|
|
57
|
-
if (typeof value === 'object' && value.fields) {
|
|
58
|
-
configs[key] = value;
|
|
59
|
-
if (!configs[key].name)
|
|
60
|
-
configs[key].name = key;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
catch (e) {
|
|
66
|
-
console.error(`Error loading object config from ${file}:`, e);
|
|
67
|
-
}
|
|
5
|
+
const registry_1 = require("./registry");
|
|
6
|
+
const metadata_1 = require("@objectql/metadata");
|
|
7
|
+
class MetadataLoader extends metadata_1.MetadataLoader {
|
|
8
|
+
constructor(registry) {
|
|
9
|
+
super(registry);
|
|
10
|
+
(0, metadata_1.registerObjectQLPlugins)(this);
|
|
68
11
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
try {
|
|
79
|
-
// Check if we should ignore .ts if .js exists?
|
|
80
|
-
// Or assume env handles it.
|
|
81
|
-
// If we are in `dist`, `src` shouldn't be there usually.
|
|
82
|
-
const hookModule = require(file);
|
|
83
|
-
// Default export or named exports?
|
|
84
|
-
// Convention: export const listenTo = 'objectName';
|
|
85
|
-
// or filename based: 'project.hook.js' -> 'project' (flaky)
|
|
86
|
-
let objectName = hookModule.listenTo;
|
|
87
|
-
if (!objectName) {
|
|
88
|
-
// Try to guess from filename?
|
|
89
|
-
// project.hook.ts -> project
|
|
90
|
-
const basename = path.basename(file);
|
|
91
|
-
const match = basename.match(/^(.+)\.hook\.(ts|js)$/);
|
|
92
|
-
if (match) {
|
|
93
|
-
objectName = match[1];
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
if (objectName && configs[objectName]) {
|
|
97
|
-
if (!configs[objectName].listeners) {
|
|
98
|
-
configs[objectName].listeners = {};
|
|
99
|
-
}
|
|
100
|
-
const listeners = configs[objectName].listeners;
|
|
101
|
-
// Merge exported functions into listeners
|
|
102
|
-
// Common hooks: beforeFind, afterFind, beforeCreate, etc.
|
|
103
|
-
const hookNames = [
|
|
104
|
-
'beforeFind', 'afterFind',
|
|
105
|
-
'beforeCreate', 'afterCreate',
|
|
106
|
-
'beforeUpdate', 'afterUpdate',
|
|
107
|
-
'beforeDelete', 'afterDelete'
|
|
108
|
-
];
|
|
109
|
-
for (const name of hookNames) {
|
|
110
|
-
if (typeof hookModule[name] === 'function') {
|
|
111
|
-
listeners[name] = hookModule[name];
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
// Support default export having listeners object?
|
|
115
|
-
if (hookModule.default && typeof hookModule.default === 'object') {
|
|
116
|
-
Object.assign(listeners, hookModule.default);
|
|
117
|
-
}
|
|
118
|
-
// Load Actions
|
|
119
|
-
// Convention: export const actions = { myAction: (ctx, params) => ... }
|
|
120
|
-
// OR export function myAction(ctx, params) ... (Ambiguous with hooks? No, hooks have explicit names)
|
|
121
|
-
// Safer: look for `actions` export.
|
|
122
|
-
if (hookModule.actions && typeof hookModule.actions === 'object') {
|
|
123
|
-
if (!configs[objectName].actions) {
|
|
124
|
-
configs[objectName].actions = {};
|
|
125
|
-
}
|
|
126
|
-
for (const [actionName, handler] of Object.entries(hookModule.actions)) {
|
|
127
|
-
// We might have metadata from YAML already
|
|
128
|
-
if (!configs[objectName].actions[actionName]) {
|
|
129
|
-
configs[objectName].actions[actionName] = {};
|
|
130
|
-
}
|
|
131
|
-
// Attach handler
|
|
132
|
-
configs[objectName].actions[actionName].handler = handler;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
catch (e) {
|
|
138
|
-
console.error(`Error loading hook from ${file}:`, e);
|
|
139
|
-
}
|
|
12
|
+
}
|
|
13
|
+
exports.MetadataLoader = MetadataLoader;
|
|
14
|
+
function loadObjectConfigs(dir) {
|
|
15
|
+
const registry = new registry_1.MetadataRegistry();
|
|
16
|
+
const loader = new MetadataLoader(registry);
|
|
17
|
+
loader.load(dir);
|
|
18
|
+
const result = {};
|
|
19
|
+
for (const obj of registry.list('object')) {
|
|
20
|
+
result[obj.name] = obj;
|
|
140
21
|
}
|
|
141
|
-
return
|
|
22
|
+
return result;
|
|
142
23
|
}
|
|
143
24
|
//# sourceMappingURL=loader.js.map
|
package/dist/loader.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":";;;AAWA,8CASC;AApBD,yCAA8C;AAE9C,iDAA2F;AAE3F,MAAa,cAAe,SAAQ,yBAAU;IAC1C,YAAY,QAA0B;QAClC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChB,IAAA,kCAAuB,EAAC,IAAI,CAAC,CAAC;IAClC,CAAC;CACJ;AALD,wCAKC;AAED,SAAgB,iBAAiB,CAAC,GAAW;IACzC,MAAM,QAAQ,GAAG,IAAI,2BAAgB,EAAE,CAAC;IACxC,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjB,MAAM,MAAM,GAAiC,EAAE,CAAC;IAChD,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAe,QAAQ,CAAC,EAAE,CAAC;QACtD,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC;IAC3B,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC"}
|
package/dist/metadata.d.ts
CHANGED
package/dist/registry.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MetadataRegistry = void 0;
|
|
4
|
+
const metadata_1 = require("@objectql/metadata");
|
|
5
|
+
class MetadataRegistry extends metadata_1.MetadataRegistry {
|
|
6
|
+
}
|
|
7
|
+
exports.MetadataRegistry = MetadataRegistry;
|
|
8
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":";;;AAAA,iDAAgF;AAGhF,MAAa,gBAAiB,SAAQ,2BAAY;CAEjD;AAFD,4CAEC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -2,15 +2,23 @@ import { ObjectRepository } from "./repository";
|
|
|
2
2
|
import { ObjectConfig } from "./metadata";
|
|
3
3
|
import { Driver } from "./driver";
|
|
4
4
|
import { UnifiedQuery, FilterCriterion } from "./query";
|
|
5
|
+
import { MetadataRegistry } from "./registry";
|
|
5
6
|
export { ObjectConfig } from "./metadata";
|
|
7
|
+
export { MetadataRegistry } from "./registry";
|
|
6
8
|
export interface ObjectQLConfig {
|
|
9
|
+
registry?: MetadataRegistry;
|
|
7
10
|
datasources: Record<string, Driver>;
|
|
8
11
|
objects?: Record<string, ObjectConfig>;
|
|
12
|
+
packages?: string[];
|
|
9
13
|
}
|
|
10
14
|
export interface IObjectQL {
|
|
11
15
|
getObject(name: string): ObjectConfig | undefined;
|
|
12
16
|
getConfigs(): Record<string, ObjectConfig>;
|
|
13
17
|
datasource(name: string): Driver;
|
|
18
|
+
init(): Promise<void>;
|
|
19
|
+
addPackage(name: string): void;
|
|
20
|
+
removePackage(name: string): void;
|
|
21
|
+
metadata: MetadataRegistry;
|
|
14
22
|
}
|
|
15
23
|
export interface HookContext<T = any> {
|
|
16
24
|
ctx: ObjectQLContext;
|
package/dist/types.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MetadataRegistry = void 0;
|
|
4
|
+
var registry_1 = require("./registry");
|
|
5
|
+
Object.defineProperty(exports, "MetadataRegistry", { enumerable: true, get: function () { return registry_1.MetadataRegistry; } });
|
|
3
6
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AAOA,uCAA8C;AAArC,4GAAA,gBAAgB,OAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectql/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"test": "jest"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"
|
|
11
|
+
"@objectql/metadata": "*",
|
|
12
|
+
"fast-glob": "^3.3.2",
|
|
12
13
|
"js-yaml": "^4.1.1"
|
|
13
14
|
}
|
|
14
15
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,33 +1,53 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
|
|
1
3
|
export * from './metadata';
|
|
2
4
|
export * from './types';
|
|
3
5
|
export * from './driver';
|
|
4
6
|
export * from './repository';
|
|
5
7
|
export * from './query';
|
|
8
|
+
export * from './registry';
|
|
9
|
+
export * from './loader';
|
|
6
10
|
|
|
7
11
|
import { ObjectConfig } from './metadata';
|
|
8
12
|
import { ObjectQLContext, ObjectQLContextOptions, IObjectQL, ObjectQLConfig } from './types';
|
|
9
13
|
import { ObjectRepository } from './repository';
|
|
10
14
|
import { Driver } from './driver';
|
|
11
|
-
import {
|
|
15
|
+
import { MetadataLoader } from './loader';
|
|
16
|
+
import { MetadataRegistry } from './registry';
|
|
12
17
|
|
|
13
18
|
export class ObjectQL implements IObjectQL {
|
|
14
|
-
|
|
19
|
+
public metadata: MetadataRegistry;
|
|
20
|
+
private loader: MetadataLoader;
|
|
15
21
|
private datasources: Record<string, Driver> = {};
|
|
16
22
|
|
|
17
23
|
constructor(config: ObjectQLConfig) {
|
|
24
|
+
this.metadata = config.registry || new MetadataRegistry();
|
|
25
|
+
this.loader = new MetadataLoader(this.metadata);
|
|
18
26
|
this.datasources = config.datasources;
|
|
27
|
+
|
|
19
28
|
if (config.objects) {
|
|
20
|
-
for (const obj of Object.
|
|
29
|
+
for (const [key, obj] of Object.entries(config.objects)) {
|
|
21
30
|
this.registerObject(obj);
|
|
22
31
|
}
|
|
23
32
|
}
|
|
33
|
+
if (config.packages) {
|
|
34
|
+
for (const name of config.packages) {
|
|
35
|
+
this.addPackage(name);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
24
38
|
}
|
|
25
39
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
40
|
+
addPackage(name: string) {
|
|
41
|
+
this.loader.loadPackage(name);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
removePackage(name: string) {
|
|
46
|
+
this.metadata.unregisterPackage(name);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
loadFromDirectory(dir: string, packageName?: string) {
|
|
50
|
+
this.loader.load(dir, packageName);
|
|
31
51
|
}
|
|
32
52
|
|
|
33
53
|
createContext(options: ObjectQLContextOptions): ObjectQLContext {
|
|
@@ -50,14 +70,12 @@ export class ObjectQL implements IObjectQL {
|
|
|
50
70
|
try {
|
|
51
71
|
trx = await driver.beginTransaction();
|
|
52
72
|
} catch (e) {
|
|
53
|
-
// If beginTransaction fails, fail.
|
|
54
73
|
throw e;
|
|
55
74
|
}
|
|
56
75
|
|
|
57
76
|
const trxCtx: ObjectQLContext = {
|
|
58
77
|
...ctx,
|
|
59
78
|
transactionHandle: trx,
|
|
60
|
-
// Nested transaction simply reuses the current one (flat transaction)
|
|
61
79
|
transaction: async (cb) => cb(trxCtx)
|
|
62
80
|
};
|
|
63
81
|
|
|
@@ -86,15 +104,24 @@ export class ObjectQL implements IObjectQL {
|
|
|
86
104
|
}
|
|
87
105
|
}
|
|
88
106
|
}
|
|
89
|
-
this.
|
|
107
|
+
this.metadata.register('object', {
|
|
108
|
+
type: 'object',
|
|
109
|
+
id: object.name,
|
|
110
|
+
content: object
|
|
111
|
+
});
|
|
90
112
|
}
|
|
91
113
|
|
|
92
114
|
getObject(name: string): ObjectConfig | undefined {
|
|
93
|
-
return this.
|
|
115
|
+
return this.metadata.get<ObjectConfig>('object', name);
|
|
94
116
|
}
|
|
95
117
|
|
|
96
118
|
getConfigs(): Record<string, ObjectConfig> {
|
|
97
|
-
|
|
119
|
+
const result: Record<string, ObjectConfig> = {};
|
|
120
|
+
const objects = this.metadata.list<ObjectConfig>('object');
|
|
121
|
+
for (const obj of objects) {
|
|
122
|
+
result[obj.name] = obj;
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
98
125
|
}
|
|
99
126
|
|
|
100
127
|
datasource(name: string): Driver {
|
|
@@ -104,4 +131,29 @@ export class ObjectQL implements IObjectQL {
|
|
|
104
131
|
}
|
|
105
132
|
return driver;
|
|
106
133
|
}
|
|
134
|
+
|
|
135
|
+
async init() {
|
|
136
|
+
const ctx = this.createContext({ isSystem: true });
|
|
137
|
+
const objects = this.metadata.list<ObjectConfig>('object');
|
|
138
|
+
for (const obj of objects) {
|
|
139
|
+
if (obj.data && obj.data.length > 0) {
|
|
140
|
+
console.log(`Initializing data for object ${obj.name}...`);
|
|
141
|
+
const repo = ctx.object(obj.name);
|
|
142
|
+
for (const record of obj.data) {
|
|
143
|
+
try {
|
|
144
|
+
if (record._id) {
|
|
145
|
+
const existing = await repo.findOne(record._id);
|
|
146
|
+
if (existing) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
await repo.create(record);
|
|
151
|
+
console.log(`Inserted init data for ${obj.name}: ${record._id || 'unknown id'}`);
|
|
152
|
+
} catch (e) {
|
|
153
|
+
console.error(`Failed to insert init data for ${obj.name}:`, e);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
107
159
|
}
|