@objectstack/objectql 0.0.1 → 0.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/dist/index.d.ts +40 -2
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +157 -6
- package/dist/registry.d.ts +1 -0
- package/dist/registry.d.ts.map +1 -0
- package/package.json +7 -6
- package/src/index.ts +189 -4
- package/tsconfig.json +6 -10
- package/dist/engine.d.ts +0 -40
- package/dist/engine.js +0 -139
- package/src/engine.ts +0 -168
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,41 @@
|
|
|
1
|
-
|
|
1
|
+
import { DriverInterface, DriverOptions } from '@objectstack/spec';
|
|
2
2
|
export { SchemaRegistry } from './registry';
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Host Context provided to plugins
|
|
5
|
+
*/
|
|
6
|
+
export interface PluginContext {
|
|
7
|
+
ql: ObjectQL;
|
|
8
|
+
logger: Console;
|
|
9
|
+
[key: string]: any;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* ObjectQL Engine
|
|
13
|
+
*/
|
|
14
|
+
export declare class ObjectQL {
|
|
15
|
+
private drivers;
|
|
16
|
+
private defaultDriver;
|
|
17
|
+
private hostContext;
|
|
18
|
+
constructor(hostContext?: Record<string, any>);
|
|
19
|
+
/**
|
|
20
|
+
* Load and Register a Plugin
|
|
21
|
+
*/
|
|
22
|
+
use(manifestPart: any, runtimePart?: any): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Register a new storage driver
|
|
25
|
+
*/
|
|
26
|
+
registerDriver(driver: DriverInterface, isDefault?: boolean): void;
|
|
27
|
+
/**
|
|
28
|
+
* Helper to get the target driver
|
|
29
|
+
*/
|
|
30
|
+
private getDriver;
|
|
31
|
+
/**
|
|
32
|
+
* Initialize the engine and all registered drivers
|
|
33
|
+
*/
|
|
34
|
+
init(): Promise<void>;
|
|
35
|
+
destroy(): Promise<void>;
|
|
36
|
+
find(object: string, filters?: any, options?: DriverOptions): Promise<Record<string, any>[]>;
|
|
37
|
+
insert(object: string, data: Record<string, any>, options?: DriverOptions): Promise<Record<string, any>>;
|
|
38
|
+
update(object: string, id: string, data: Record<string, any>, options?: DriverOptions): Promise<Record<string, any>>;
|
|
39
|
+
delete(object: string, id: string, options?: DriverOptions): Promise<boolean>;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAiC,MAAM,mBAAmB,CAAC;AAIlG,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,QAAQ,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAEhB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,OAAO,CAAsC;IACrD,OAAO,CAAC,aAAa,CAAuB;IAG5C,OAAO,CAAC,WAAW,CAA2B;gBAElC,WAAW,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM;IAKjD;;OAEG;IACG,GAAG,CAAC,YAAY,EAAE,GAAG,EAAE,WAAW,CAAC,EAAE,GAAG;IA4D9C;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,eAAe,EAAE,SAAS,GAAE,OAAe;IAclE;;OAEG;IACH,OAAO,CAAC,SAAS;IASjB;;OAEG;IACG,IAAI;IAYJ,OAAO;IAUP,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,GAAQ,EAAE,OAAO,CAAC,EAAE,aAAa;IAmB/D,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa;IAYzE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa;IAMrF,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa;CAKjE"}
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,159 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
exports.ObjectQL = exports.SchemaRegistry = void 0;
|
|
4
|
+
const registry_1 = require("./registry");
|
|
5
|
+
// Export Registry for consumers
|
|
6
|
+
var registry_2 = require("./registry");
|
|
7
|
+
Object.defineProperty(exports, "SchemaRegistry", { enumerable: true, get: function () { return registry_2.SchemaRegistry; } });
|
|
8
|
+
/**
|
|
9
|
+
* ObjectQL Engine
|
|
10
|
+
*/
|
|
11
|
+
class ObjectQL {
|
|
12
|
+
constructor(hostContext = {}) {
|
|
13
|
+
this.drivers = new Map();
|
|
14
|
+
this.defaultDriver = null;
|
|
15
|
+
// Host provided context additions (e.g. Server router)
|
|
16
|
+
this.hostContext = {};
|
|
17
|
+
this.hostContext = hostContext;
|
|
18
|
+
console.log(`[ObjectQL] Engine Instance Created`);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Load and Register a Plugin
|
|
22
|
+
*/
|
|
23
|
+
async use(manifestPart, runtimePart) {
|
|
24
|
+
// 1. Validate / Register Manifest
|
|
25
|
+
if (manifestPart) {
|
|
26
|
+
// 1. Handle Module Imports (commonjs/esm interop)
|
|
27
|
+
// If the passed object is a module namespace with a default export, use that.
|
|
28
|
+
const manifest = manifestPart.default || manifestPart;
|
|
29
|
+
// In a real scenario, we might strictly parse this using Zod
|
|
30
|
+
// For now, simple ID check
|
|
31
|
+
const id = manifest.id || manifest.name;
|
|
32
|
+
if (!id) {
|
|
33
|
+
console.warn(`[ObjectQL] Plugin manifest missing ID (keys: ${Object.keys(manifest)})`, manifest);
|
|
34
|
+
// Don't return, try to proceed if it looks like an App (Apps might use 'name' instead of 'id')
|
|
35
|
+
// return;
|
|
36
|
+
}
|
|
37
|
+
console.log(`[ObjectQL] Loading Plugin: ${id}`);
|
|
38
|
+
registry_1.SchemaRegistry.registerPlugin(manifest);
|
|
39
|
+
// Register Objects from App/Plugin
|
|
40
|
+
if (manifest.objects) {
|
|
41
|
+
for (const obj of manifest.objects) {
|
|
42
|
+
// Ensure object name is registered globally
|
|
43
|
+
registry_1.SchemaRegistry.registerObject(obj);
|
|
44
|
+
console.log(`[ObjectQL] Registered Object: ${obj.name}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Register contributions
|
|
48
|
+
if (manifest.contributes?.kinds) {
|
|
49
|
+
for (const kind of manifest.contributes.kinds) {
|
|
50
|
+
registry_1.SchemaRegistry.registerKind(kind);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Register Data Seeding (Lazy execution or immediate?)
|
|
54
|
+
// We store it in a temporary registry or execute immediately if engine is ready.
|
|
55
|
+
// Since `use` is init time, we might need to store it and run later in `seed()`.
|
|
56
|
+
// For this MVP, let's attach it to the manifest object in registry so Kernel can find it.
|
|
57
|
+
}
|
|
58
|
+
// 2. Execute Runtime
|
|
59
|
+
if (runtimePart) {
|
|
60
|
+
const pluginDef = runtimePart.default || runtimePart;
|
|
61
|
+
if (pluginDef.onEnable) {
|
|
62
|
+
const context = {
|
|
63
|
+
ql: this,
|
|
64
|
+
logger: console,
|
|
65
|
+
// Expose the driver registry helper explicitly if needed
|
|
66
|
+
drivers: {
|
|
67
|
+
register: (driver) => this.registerDriver(driver)
|
|
68
|
+
},
|
|
69
|
+
...this.hostContext
|
|
70
|
+
};
|
|
71
|
+
await pluginDef.onEnable(context);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Register a new storage driver
|
|
77
|
+
*/
|
|
78
|
+
registerDriver(driver, isDefault = false) {
|
|
79
|
+
if (this.drivers.has(driver.name)) {
|
|
80
|
+
console.warn(`[ObjectQL] Driver ${driver.name} is already registered. Skipping.`);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
this.drivers.set(driver.name, driver);
|
|
84
|
+
console.log(`[ObjectQL] Registered driver: ${driver.name} v${driver.version}`);
|
|
85
|
+
if (isDefault || this.drivers.size === 1) {
|
|
86
|
+
this.defaultDriver = driver.name;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Helper to get the target driver
|
|
91
|
+
*/
|
|
92
|
+
getDriver(_object) {
|
|
93
|
+
// TODO: Look up Object definition to see if it specifies a specific datasource/driver
|
|
94
|
+
// For now, always return default
|
|
95
|
+
if (!this.defaultDriver) {
|
|
96
|
+
throw new Error('[ObjectQL] No drivers registered!');
|
|
97
|
+
}
|
|
98
|
+
return this.drivers.get(this.defaultDriver);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Initialize the engine and all registered drivers
|
|
102
|
+
*/
|
|
103
|
+
async init() {
|
|
104
|
+
console.log('[ObjectQL] Initializing drivers...');
|
|
105
|
+
for (const [name, driver] of this.drivers) {
|
|
106
|
+
try {
|
|
107
|
+
await driver.connect();
|
|
108
|
+
}
|
|
109
|
+
catch (e) {
|
|
110
|
+
console.error(`[ObjectQL] Failed to connect driver ${name}`, e);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// In a real app, we would sync schemas here
|
|
114
|
+
}
|
|
115
|
+
async destroy() {
|
|
116
|
+
for (const driver of this.drivers.values()) {
|
|
117
|
+
await driver.disconnect();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// ============================================
|
|
121
|
+
// Data Access Methods
|
|
122
|
+
// ============================================
|
|
123
|
+
async find(object, filters = {}, options) {
|
|
124
|
+
const driver = this.getDriver(object);
|
|
125
|
+
console.log(`[ObjectQL] Finding ${object} on ${driver.name}...`);
|
|
126
|
+
// Transform simplified filters to QueryAST
|
|
127
|
+
// This is a simplified "Mock" transform.
|
|
128
|
+
// Real implementation would parse complex JSON or FilterBuilders.
|
|
129
|
+
const ast = {
|
|
130
|
+
object, // Add missing required field
|
|
131
|
+
// Pass through if it looks like AST, otherwise empty
|
|
132
|
+
// In this demo, we assume the caller passes a simplified object or raw AST
|
|
133
|
+
filters: filters.filters || undefined,
|
|
134
|
+
top: filters.top || 100,
|
|
135
|
+
sort: filters.sort || []
|
|
136
|
+
};
|
|
137
|
+
return driver.find(object, ast, options);
|
|
138
|
+
}
|
|
139
|
+
async insert(object, data, options) {
|
|
140
|
+
const driver = this.getDriver(object);
|
|
141
|
+
console.log(`[ObjectQL] Creating ${object} on ${driver.name}...`);
|
|
142
|
+
// 1. Validate Schema
|
|
143
|
+
// 2. Run "Before Insert" Triggers
|
|
144
|
+
const result = await driver.create(object, data, options);
|
|
145
|
+
// 3. Run "After Insert" Triggers
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
async update(object, id, data, options) {
|
|
149
|
+
const driver = this.getDriver(object);
|
|
150
|
+
console.log(`[ObjectQL] Updating ${object} ${id}...`);
|
|
151
|
+
return driver.update(object, id, data, options);
|
|
152
|
+
}
|
|
153
|
+
async delete(object, id, options) {
|
|
154
|
+
const driver = this.getDriver(object);
|
|
155
|
+
console.log(`[ObjectQL] Deleting ${object} ${id}...`);
|
|
156
|
+
return driver.delete(object, id, options);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
exports.ObjectQL = ObjectQL;
|
package/dist/registry.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,GAAG,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE5E;;;GAGG;AACH,qBAAa,cAAc;IAEzB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAuC;IAE9D;;;;;OAKG;IACH,MAAM,CAAC,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,GAAE,MAAM,CAAqB;IAcnF;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAI5D;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,EAAE;IAItC;;OAEG;IACH,MAAM,CAAC,kBAAkB,IAAI,MAAM,EAAE;IAQrC;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,aAAa;IAI3C,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAIzD,MAAM,CAAC,aAAa,IAAI,aAAa,EAAE;IAIvC;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG;IAI3B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS;IAI5C,MAAM,CAAC,UAAU,IAAI,GAAG,EAAE;IAI1B;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,mBAAmB;IAInD,MAAM,CAAC,aAAa,IAAI,mBAAmB,EAAE;IAI7C;;OAEG;IACH,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE;IAIzD,MAAM,CAAC,WAAW,IAAI;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE;CAGxD"}
|
package/package.json
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/objectql",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "ObjectQL
|
|
5
|
-
"main": "
|
|
6
|
-
"types": "
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Isomorphic ObjectQL Engine for ObjectStack",
|
|
5
|
+
"main": "src/index.ts",
|
|
6
|
+
"types": "src/index.ts",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"@objectstack/spec": "0.1.1"
|
|
9
9
|
},
|
|
10
10
|
"devDependencies": {
|
|
11
|
-
"typescript": "^5.0.0"
|
|
11
|
+
"typescript": "^5.0.0",
|
|
12
|
+
"vitest": "^1.0.0"
|
|
12
13
|
},
|
|
13
14
|
"scripts": {
|
|
14
15
|
"build": "tsc",
|
|
15
|
-
"
|
|
16
|
+
"test": "vitest"
|
|
16
17
|
}
|
|
17
18
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,191 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { DriverInterface, DriverOptions, QueryAST, ObjectStackManifest } from '@objectstack/spec';
|
|
2
|
+
import { SchemaRegistry } from './registry';
|
|
3
|
+
|
|
4
|
+
// Export Registry for consumers
|
|
3
5
|
export { SchemaRegistry } from './registry';
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Host Context provided to plugins
|
|
9
|
+
*/
|
|
10
|
+
export interface PluginContext {
|
|
11
|
+
ql: ObjectQL;
|
|
12
|
+
logger: Console;
|
|
13
|
+
// Extensible map for host-specific globals (like HTTP Router, etc.)
|
|
14
|
+
[key: string]: any;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* ObjectQL Engine
|
|
19
|
+
*/
|
|
20
|
+
export class ObjectQL {
|
|
21
|
+
private drivers = new Map<string, DriverInterface>();
|
|
22
|
+
private defaultDriver: string | null = null;
|
|
23
|
+
|
|
24
|
+
// Host provided context additions (e.g. Server router)
|
|
25
|
+
private hostContext: Record<string, any> = {};
|
|
26
|
+
|
|
27
|
+
constructor(hostContext: Record<string, any> = {}) {
|
|
28
|
+
this.hostContext = hostContext;
|
|
29
|
+
console.log(`[ObjectQL] Engine Instance Created`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Load and Register a Plugin
|
|
34
|
+
*/
|
|
35
|
+
async use(manifestPart: any, runtimePart?: any) {
|
|
36
|
+
// 1. Validate / Register Manifest
|
|
37
|
+
if (manifestPart) {
|
|
38
|
+
// 1. Handle Module Imports (commonjs/esm interop)
|
|
39
|
+
// If the passed object is a module namespace with a default export, use that.
|
|
40
|
+
const manifest = manifestPart.default || manifestPart;
|
|
41
|
+
|
|
42
|
+
// In a real scenario, we might strictly parse this using Zod
|
|
43
|
+
// For now, simple ID check
|
|
44
|
+
const id = manifest.id || manifest.name;
|
|
45
|
+
if (!id) {
|
|
46
|
+
console.warn(`[ObjectQL] Plugin manifest missing ID (keys: ${Object.keys(manifest)})`, manifest);
|
|
47
|
+
// Don't return, try to proceed if it looks like an App (Apps might use 'name' instead of 'id')
|
|
48
|
+
// return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log(`[ObjectQL] Loading Plugin: ${id}`);
|
|
52
|
+
SchemaRegistry.registerPlugin(manifest as ObjectStackManifest);
|
|
53
|
+
|
|
54
|
+
// Register Objects from App/Plugin
|
|
55
|
+
if (manifest.objects) {
|
|
56
|
+
for (const obj of manifest.objects) {
|
|
57
|
+
// Ensure object name is registered globally
|
|
58
|
+
SchemaRegistry.registerObject(obj);
|
|
59
|
+
console.log(`[ObjectQL] Registered Object: ${obj.name}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Register contributions
|
|
64
|
+
if (manifest.contributes?.kinds) {
|
|
65
|
+
for (const kind of manifest.contributes.kinds) {
|
|
66
|
+
SchemaRegistry.registerKind(kind);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Register Data Seeding (Lazy execution or immediate?)
|
|
71
|
+
// We store it in a temporary registry or execute immediately if engine is ready.
|
|
72
|
+
// Since `use` is init time, we might need to store it and run later in `seed()`.
|
|
73
|
+
// For this MVP, let's attach it to the manifest object in registry so Kernel can find it.
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 2. Execute Runtime
|
|
77
|
+
if (runtimePart) {
|
|
78
|
+
const pluginDef = (runtimePart as any).default || runtimePart;
|
|
79
|
+
if (pluginDef.onEnable) {
|
|
80
|
+
const context: PluginContext = {
|
|
81
|
+
ql: this,
|
|
82
|
+
logger: console,
|
|
83
|
+
// Expose the driver registry helper explicitly if needed
|
|
84
|
+
drivers: {
|
|
85
|
+
register: (driver: DriverInterface) => this.registerDriver(driver)
|
|
86
|
+
},
|
|
87
|
+
...this.hostContext
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
await pluginDef.onEnable(context);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Register a new storage driver
|
|
97
|
+
*/
|
|
98
|
+
registerDriver(driver: DriverInterface, isDefault: boolean = false) {
|
|
99
|
+
if (this.drivers.has(driver.name)) {
|
|
100
|
+
console.warn(`[ObjectQL] Driver ${driver.name} is already registered. Skipping.`);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
this.drivers.set(driver.name, driver);
|
|
105
|
+
console.log(`[ObjectQL] Registered driver: ${driver.name} v${driver.version}`);
|
|
106
|
+
|
|
107
|
+
if (isDefault || this.drivers.size === 1) {
|
|
108
|
+
this.defaultDriver = driver.name;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Helper to get the target driver
|
|
114
|
+
*/
|
|
115
|
+
private getDriver(_object: string): DriverInterface {
|
|
116
|
+
// TODO: Look up Object definition to see if it specifies a specific datasource/driver
|
|
117
|
+
// For now, always return default
|
|
118
|
+
if (!this.defaultDriver) {
|
|
119
|
+
throw new Error('[ObjectQL] No drivers registered!');
|
|
120
|
+
}
|
|
121
|
+
return this.drivers.get(this.defaultDriver)!;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Initialize the engine and all registered drivers
|
|
126
|
+
*/
|
|
127
|
+
async init() {
|
|
128
|
+
console.log('[ObjectQL] Initializing drivers...');
|
|
129
|
+
for (const [name, driver] of this.drivers) {
|
|
130
|
+
try {
|
|
131
|
+
await driver.connect();
|
|
132
|
+
} catch (e) {
|
|
133
|
+
console.error(`[ObjectQL] Failed to connect driver ${name}`, e);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// In a real app, we would sync schemas here
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async destroy() {
|
|
140
|
+
for (const driver of this.drivers.values()) {
|
|
141
|
+
await driver.disconnect();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ============================================
|
|
146
|
+
// Data Access Methods
|
|
147
|
+
// ============================================
|
|
148
|
+
|
|
149
|
+
async find(object: string, filters: any = {}, options?: DriverOptions) {
|
|
150
|
+
const driver = this.getDriver(object);
|
|
151
|
+
console.log(`[ObjectQL] Finding ${object} on ${driver.name}...`);
|
|
152
|
+
|
|
153
|
+
// Transform simplified filters to QueryAST
|
|
154
|
+
// This is a simplified "Mock" transform.
|
|
155
|
+
// Real implementation would parse complex JSON or FilterBuilders.
|
|
156
|
+
const ast: QueryAST = {
|
|
157
|
+
object, // Add missing required field
|
|
158
|
+
// Pass through if it looks like AST, otherwise empty
|
|
159
|
+
// In this demo, we assume the caller passes a simplified object or raw AST
|
|
160
|
+
filters: filters.filters || undefined,
|
|
161
|
+
top: filters.top || 100,
|
|
162
|
+
sort: filters.sort || []
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
return driver.find(object, ast, options);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async insert(object: string, data: Record<string, any>, options?: DriverOptions) {
|
|
169
|
+
const driver = this.getDriver(object);
|
|
170
|
+
console.log(`[ObjectQL] Creating ${object} on ${driver.name}...`);
|
|
171
|
+
// 1. Validate Schema
|
|
172
|
+
// 2. Run "Before Insert" Triggers
|
|
173
|
+
|
|
174
|
+
const result = await driver.create(object, data, options);
|
|
175
|
+
|
|
176
|
+
// 3. Run "After Insert" Triggers
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async update(object: string, id: string, data: Record<string, any>, options?: DriverOptions) {
|
|
181
|
+
const driver = this.getDriver(object);
|
|
182
|
+
console.log(`[ObjectQL] Updating ${object} ${id}...`);
|
|
183
|
+
return driver.update(object, id, data, options);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async delete(object: string, id: string, options?: DriverOptions) {
|
|
187
|
+
const driver = this.getDriver(object);
|
|
188
|
+
console.log(`[ObjectQL] Deleting ${object} ${id}...`);
|
|
189
|
+
return driver.delete(object, id, options);
|
|
190
|
+
}
|
|
191
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
+
"extends": "../../tsconfig.json",
|
|
3
|
+
"include": ["src/**/*"],
|
|
4
|
+
"exclude": ["node_modules", "dist"],
|
|
2
5
|
"compilerOptions": {
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
"outDir": "./dist",
|
|
7
|
-
"strict": true,
|
|
8
|
-
"esModuleInterop": true,
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"forceConsistentCasingInFileNames": true
|
|
11
|
-
},
|
|
12
|
-
"include": ["src/**/*"]
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"rootDir": "src"
|
|
8
|
+
}
|
|
13
9
|
}
|
package/dist/engine.d.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { DriverInterface, DriverOptions } from '@objectstack/spec';
|
|
2
|
-
/**
|
|
3
|
-
* Host Context provided to plugins
|
|
4
|
-
*/
|
|
5
|
-
export interface PluginContext {
|
|
6
|
-
ql: ObjectQL;
|
|
7
|
-
logger: Console;
|
|
8
|
-
[key: string]: any;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* ObjectQL Engine
|
|
12
|
-
*/
|
|
13
|
-
export declare class ObjectQL {
|
|
14
|
-
private drivers;
|
|
15
|
-
private defaultDriver;
|
|
16
|
-
private plugins;
|
|
17
|
-
private hostContext;
|
|
18
|
-
constructor(hostContext?: Record<string, any>);
|
|
19
|
-
/**
|
|
20
|
-
* Load and Register a Plugin
|
|
21
|
-
*/
|
|
22
|
-
use(manifestPart: any, runtimePart?: any): Promise<void>;
|
|
23
|
-
/**
|
|
24
|
-
* Register a new storage driver
|
|
25
|
-
*/
|
|
26
|
-
registerDriver(driver: DriverInterface, isDefault?: boolean): void;
|
|
27
|
-
/**
|
|
28
|
-
* Helper to get the target driver
|
|
29
|
-
*/
|
|
30
|
-
private getDriver;
|
|
31
|
-
/**
|
|
32
|
-
* Initialize the engine and all registered drivers
|
|
33
|
-
*/
|
|
34
|
-
init(): Promise<void>;
|
|
35
|
-
destroy(): Promise<void>;
|
|
36
|
-
find(object: string, filters?: any, options?: DriverOptions): Promise<Record<string, any>[]>;
|
|
37
|
-
insert(object: string, data: Record<string, any>, options?: DriverOptions): Promise<Record<string, any>>;
|
|
38
|
-
update(object: string, id: string, data: Record<string, any>, options?: DriverOptions): Promise<Record<string, any>>;
|
|
39
|
-
delete(object: string, id: string, options?: DriverOptions): Promise<boolean>;
|
|
40
|
-
}
|
package/dist/engine.js
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ObjectQL = void 0;
|
|
4
|
-
const registry_1 = require("./registry");
|
|
5
|
-
/**
|
|
6
|
-
* ObjectQL Engine
|
|
7
|
-
*/
|
|
8
|
-
class ObjectQL {
|
|
9
|
-
constructor(hostContext = {}) {
|
|
10
|
-
this.drivers = new Map();
|
|
11
|
-
this.defaultDriver = null;
|
|
12
|
-
this.plugins = new Map();
|
|
13
|
-
// Host provided context additions (e.g. Server router)
|
|
14
|
-
this.hostContext = {};
|
|
15
|
-
this.hostContext = hostContext;
|
|
16
|
-
console.log(`[ObjectQL] Engine Instance Created`);
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Load and Register a Plugin
|
|
20
|
-
*/
|
|
21
|
-
async use(manifestPart, runtimePart) {
|
|
22
|
-
// 1. Validate / Register Manifest
|
|
23
|
-
if (manifestPart) {
|
|
24
|
-
// In a real scenario, we might strictly parse this using Zod
|
|
25
|
-
// For now, simple ID check
|
|
26
|
-
const id = manifestPart.id;
|
|
27
|
-
if (!id) {
|
|
28
|
-
console.warn('[ObjectQL] Plugin manifest missing ID', manifestPart);
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
console.log(`[ObjectQL] Loading Plugin: ${id}`);
|
|
32
|
-
registry_1.SchemaRegistry.registerPlugin(manifestPart);
|
|
33
|
-
// Register contributions
|
|
34
|
-
if (manifestPart.contributes?.kinds) {
|
|
35
|
-
for (const kind of manifestPart.contributes.kinds) {
|
|
36
|
-
registry_1.SchemaRegistry.registerKind(kind);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
// 2. Execute Runtime
|
|
41
|
-
if (runtimePart) {
|
|
42
|
-
const pluginDef = runtimePart.default || runtimePart;
|
|
43
|
-
if (pluginDef.onEnable) {
|
|
44
|
-
const context = {
|
|
45
|
-
ql: this,
|
|
46
|
-
logger: console,
|
|
47
|
-
// Expose the driver registry helper explicitly if needed
|
|
48
|
-
drivers: this, // Since `registerDriver` is on `this`, we can alias it or expose `this`
|
|
49
|
-
...this.hostContext
|
|
50
|
-
};
|
|
51
|
-
await pluginDef.onEnable(context);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Register a new storage driver
|
|
57
|
-
*/
|
|
58
|
-
registerDriver(driver, isDefault = false) {
|
|
59
|
-
if (this.drivers.has(driver.name)) {
|
|
60
|
-
console.warn(`[ObjectQL] Driver ${driver.name} is already registered. Skipping.`);
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
this.drivers.set(driver.name, driver);
|
|
64
|
-
console.log(`[ObjectQL] Registered driver: ${driver.name} v${driver.version}`);
|
|
65
|
-
if (isDefault || this.drivers.size === 1) {
|
|
66
|
-
this.defaultDriver = driver.name;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Helper to get the target driver
|
|
71
|
-
*/
|
|
72
|
-
getDriver(object) {
|
|
73
|
-
// TODO: Look up Object definition to see if it specifies a specific datasource/driver
|
|
74
|
-
// For now, always return default
|
|
75
|
-
if (!this.defaultDriver) {
|
|
76
|
-
throw new Error('[ObjectQL] No drivers registered!');
|
|
77
|
-
}
|
|
78
|
-
return this.drivers.get(this.defaultDriver);
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Initialize the engine and all registered drivers
|
|
82
|
-
*/
|
|
83
|
-
async init() {
|
|
84
|
-
console.log('[ObjectQL] Initializing drivers...');
|
|
85
|
-
for (const [name, driver] of this.drivers) {
|
|
86
|
-
try {
|
|
87
|
-
await driver.connect();
|
|
88
|
-
}
|
|
89
|
-
catch (e) {
|
|
90
|
-
console.error(`[ObjectQL] Failed to connect driver ${name}`, e);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
// In a real app, we would sync schemas here
|
|
94
|
-
}
|
|
95
|
-
async destroy() {
|
|
96
|
-
for (const driver of this.drivers.values()) {
|
|
97
|
-
await driver.disconnect();
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
// ============================================
|
|
101
|
-
// Data Access Methods
|
|
102
|
-
// ============================================
|
|
103
|
-
async find(object, filters = {}, options) {
|
|
104
|
-
const driver = this.getDriver(object);
|
|
105
|
-
console.log(`[ObjectQL] Finding ${object} on ${driver.name}...`);
|
|
106
|
-
// Transform simplified filters to QueryAST
|
|
107
|
-
// This is a simplified "Mock" transform.
|
|
108
|
-
// Real implementation would parse complex JSON or FilterBuilders.
|
|
109
|
-
const ast = {
|
|
110
|
-
object, // Add missing required field
|
|
111
|
-
// Pass through if it looks like AST, otherwise empty
|
|
112
|
-
// In this demo, we assume the caller passes a simplified object or raw AST
|
|
113
|
-
filters: filters.filters || undefined,
|
|
114
|
-
top: filters.top || 100,
|
|
115
|
-
sort: filters.sort || []
|
|
116
|
-
};
|
|
117
|
-
return driver.find(object, ast, options);
|
|
118
|
-
}
|
|
119
|
-
async insert(object, data, options) {
|
|
120
|
-
const driver = this.getDriver(object);
|
|
121
|
-
console.log(`[ObjectQL] Creating ${object} on ${driver.name}...`);
|
|
122
|
-
// 1. Validate Schema
|
|
123
|
-
// 2. Run "Before Insert" Triggers
|
|
124
|
-
const result = await driver.create(object, data, options);
|
|
125
|
-
// 3. Run "After Insert" Triggers
|
|
126
|
-
return result;
|
|
127
|
-
}
|
|
128
|
-
async update(object, id, data, options) {
|
|
129
|
-
const driver = this.getDriver(object);
|
|
130
|
-
console.log(`[ObjectQL] Updating ${object} ${id}...`);
|
|
131
|
-
return driver.update(object, id, data, options);
|
|
132
|
-
}
|
|
133
|
-
async delete(object, id, options) {
|
|
134
|
-
const driver = this.getDriver(object);
|
|
135
|
-
console.log(`[ObjectQL] Deleting ${object} ${id}...`);
|
|
136
|
-
return driver.delete(object, id, options);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
exports.ObjectQL = ObjectQL;
|
package/src/engine.ts
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import { DriverInterface, DriverOptions, QueryAST, ObjectStackManifest, ManifestSchema } from '@objectstack/spec';
|
|
2
|
-
import { SchemaRegistry } from './registry';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Host Context provided to plugins
|
|
6
|
-
*/
|
|
7
|
-
export interface PluginContext {
|
|
8
|
-
ql: ObjectQL;
|
|
9
|
-
logger: Console;
|
|
10
|
-
// Extensible map for host-specific globals (like HTTP Router, etc.)
|
|
11
|
-
[key: string]: any;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* ObjectQL Engine
|
|
16
|
-
*/
|
|
17
|
-
export class ObjectQL {
|
|
18
|
-
private drivers = new Map<string, DriverInterface>();
|
|
19
|
-
private defaultDriver: string | null = null;
|
|
20
|
-
private plugins = new Map<string, any>();
|
|
21
|
-
|
|
22
|
-
// Host provided context additions (e.g. Server router)
|
|
23
|
-
private hostContext: Record<string, any> = {};
|
|
24
|
-
|
|
25
|
-
constructor(hostContext: Record<string, any> = {}) {
|
|
26
|
-
this.hostContext = hostContext;
|
|
27
|
-
console.log(`[ObjectQL] Engine Instance Created`);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Load and Register a Plugin
|
|
32
|
-
*/
|
|
33
|
-
async use(manifestPart: any, runtimePart?: any) {
|
|
34
|
-
// 1. Validate / Register Manifest
|
|
35
|
-
if (manifestPart) {
|
|
36
|
-
// In a real scenario, we might strictly parse this using Zod
|
|
37
|
-
// For now, simple ID check
|
|
38
|
-
const id = manifestPart.id;
|
|
39
|
-
if (!id) {
|
|
40
|
-
console.warn('[ObjectQL] Plugin manifest missing ID', manifestPart);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
console.log(`[ObjectQL] Loading Plugin: ${id}`);
|
|
45
|
-
SchemaRegistry.registerPlugin(manifestPart as ObjectStackManifest);
|
|
46
|
-
|
|
47
|
-
// Register contributions
|
|
48
|
-
if (manifestPart.contributes?.kinds) {
|
|
49
|
-
for (const kind of manifestPart.contributes.kinds) {
|
|
50
|
-
SchemaRegistry.registerKind(kind);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// 2. Execute Runtime
|
|
56
|
-
if (runtimePart) {
|
|
57
|
-
const pluginDef = (runtimePart as any).default || runtimePart;
|
|
58
|
-
if (pluginDef.onEnable) {
|
|
59
|
-
const context: PluginContext = {
|
|
60
|
-
ql: this,
|
|
61
|
-
logger: console,
|
|
62
|
-
// Expose the driver registry helper explicitly if needed
|
|
63
|
-
drivers: this, // Since `registerDriver` is on `this`, we can alias it or expose `this`
|
|
64
|
-
...this.hostContext
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
await pluginDef.onEnable(context);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Register a new storage driver
|
|
74
|
-
*/
|
|
75
|
-
registerDriver(driver: DriverInterface, isDefault: boolean = false) {
|
|
76
|
-
if (this.drivers.has(driver.name)) {
|
|
77
|
-
console.warn(`[ObjectQL] Driver ${driver.name} is already registered. Skipping.`);
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
this.drivers.set(driver.name, driver);
|
|
82
|
-
console.log(`[ObjectQL] Registered driver: ${driver.name} v${driver.version}`);
|
|
83
|
-
|
|
84
|
-
if (isDefault || this.drivers.size === 1) {
|
|
85
|
-
this.defaultDriver = driver.name;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Helper to get the target driver
|
|
91
|
-
*/
|
|
92
|
-
private getDriver(object: string): DriverInterface {
|
|
93
|
-
// TODO: Look up Object definition to see if it specifies a specific datasource/driver
|
|
94
|
-
// For now, always return default
|
|
95
|
-
if (!this.defaultDriver) {
|
|
96
|
-
throw new Error('[ObjectQL] No drivers registered!');
|
|
97
|
-
}
|
|
98
|
-
return this.drivers.get(this.defaultDriver)!;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Initialize the engine and all registered drivers
|
|
103
|
-
*/
|
|
104
|
-
async init() {
|
|
105
|
-
console.log('[ObjectQL] Initializing drivers...');
|
|
106
|
-
for (const [name, driver] of this.drivers) {
|
|
107
|
-
try {
|
|
108
|
-
await driver.connect();
|
|
109
|
-
} catch (e) {
|
|
110
|
-
console.error(`[ObjectQL] Failed to connect driver ${name}`, e);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
// In a real app, we would sync schemas here
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
async destroy() {
|
|
117
|
-
for (const driver of this.drivers.values()) {
|
|
118
|
-
await driver.disconnect();
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// ============================================
|
|
123
|
-
// Data Access Methods
|
|
124
|
-
// ============================================
|
|
125
|
-
|
|
126
|
-
async find(object: string, filters: any = {}, options?: DriverOptions) {
|
|
127
|
-
const driver = this.getDriver(object);
|
|
128
|
-
console.log(`[ObjectQL] Finding ${object} on ${driver.name}...`);
|
|
129
|
-
|
|
130
|
-
// Transform simplified filters to QueryAST
|
|
131
|
-
// This is a simplified "Mock" transform.
|
|
132
|
-
// Real implementation would parse complex JSON or FilterBuilders.
|
|
133
|
-
const ast: QueryAST = {
|
|
134
|
-
object, // Add missing required field
|
|
135
|
-
// Pass through if it looks like AST, otherwise empty
|
|
136
|
-
// In this demo, we assume the caller passes a simplified object or raw AST
|
|
137
|
-
filters: filters.filters || undefined,
|
|
138
|
-
top: filters.top || 100,
|
|
139
|
-
sort: filters.sort || []
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
return driver.find(object, ast, options);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
async insert(object: string, data: Record<string, any>, options?: DriverOptions) {
|
|
146
|
-
const driver = this.getDriver(object);
|
|
147
|
-
console.log(`[ObjectQL] Creating ${object} on ${driver.name}...`);
|
|
148
|
-
// 1. Validate Schema
|
|
149
|
-
// 2. Run "Before Insert" Triggers
|
|
150
|
-
|
|
151
|
-
const result = await driver.create(object, data, options);
|
|
152
|
-
|
|
153
|
-
// 3. Run "After Insert" Triggers
|
|
154
|
-
return result;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
async update(object: string, id: string, data: Record<string, any>, options?: DriverOptions) {
|
|
158
|
-
const driver = this.getDriver(object);
|
|
159
|
-
console.log(`[ObjectQL] Updating ${object} ${id}...`);
|
|
160
|
-
return driver.update(object, id, data, options);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
async delete(object: string, id: string, options?: DriverOptions) {
|
|
164
|
-
const driver = this.getDriver(object);
|
|
165
|
-
console.log(`[ObjectQL] Deleting ${object} ${id}...`);
|
|
166
|
-
return driver.delete(object, id, options);
|
|
167
|
-
}
|
|
168
|
-
}
|