Skip to content

Commit b16bf1a

Browse files
committed
添加 ObjectQL 引擎实现,重构数据引擎以支持驱动注册和初始化逻辑
1 parent 177ab3e commit b16bf1a

File tree

3 files changed

+136
-176
lines changed

3 files changed

+136
-176
lines changed

examples/objectql/src/engine.ts

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { DriverInterface, DriverOptions, QueryAST } from '@objectstack/spec';
2+
3+
/**
4+
* ObjectQL Engine
5+
*
6+
* The core orchestration layer that sits between the API/UI and the Data Driver.
7+
* It handles:
8+
* 1. Request Validation (using Schemas)
9+
* 2. Security Enforcement (ACLs, Sharing Rules)
10+
* 3. Workflow Triggers
11+
* 4. Driver Delegation
12+
*/
13+
export class ObjectQL {
14+
private drivers = new Map<string, DriverInterface>();
15+
private defaultDriver: string | null = null;
16+
17+
constructor() {
18+
console.log(`[ObjectQL] Engine Instance Created`);
19+
}
20+
21+
/**
22+
* Register a new storage driver
23+
*/
24+
registerDriver(driver: DriverInterface, isDefault: boolean = false) {
25+
if (this.drivers.has(driver.name)) {
26+
console.warn(`[ObjectQL] Driver ${driver.name} is already registered. Skipping.`);
27+
return;
28+
}
29+
30+
this.drivers.set(driver.name, driver);
31+
console.log(`[ObjectQL] Registered driver: ${driver.name} v${driver.version}`);
32+
33+
if (isDefault || this.drivers.size === 1) {
34+
this.defaultDriver = driver.name;
35+
}
36+
}
37+
38+
/**
39+
* Helper to get the target driver
40+
*/
41+
private getDriver(object: string): DriverInterface {
42+
// TODO: Look up Object definition to see if it specifies a specific datasource/driver
43+
// For now, always return default
44+
if (!this.defaultDriver) {
45+
throw new Error('[ObjectQL] No drivers registered!');
46+
}
47+
return this.drivers.get(this.defaultDriver)!;
48+
}
49+
50+
/**
51+
* Initialize the engine and all registered drivers
52+
*/
53+
async init() {
54+
console.log('[ObjectQL] Initializing drivers...');
55+
for (const [name, driver] of this.drivers) {
56+
try {
57+
await driver.connect();
58+
} catch (e) {
59+
console.error(`[ObjectQL] Failed to connect driver ${name}`, e);
60+
}
61+
}
62+
// In a real app, we would sync schemas here
63+
}
64+
65+
async destroy() {
66+
for (const driver of this.drivers.values()) {
67+
await driver.disconnect();
68+
}
69+
}
70+
71+
// ============================================
72+
// Data Access Methods
73+
// ============================================
74+
75+
async find(object: string, filters: any = {}, options?: DriverOptions) {
76+
const driver = this.getDriver(object);
77+
console.log(`[ObjectQL] Finding ${object} on ${driver.name}...`);
78+
79+
// Transform simplified filters to QueryAST
80+
// This is a simplified "Mock" transform.
81+
// Real implementation would parse complex JSON or FilterBuilders.
82+
const ast: QueryAST = {
83+
// Pass through if it looks like AST, otherwise empty
84+
// In this demo, we assume the caller passes a simplified object or raw AST
85+
filters: filters.filters || undefined,
86+
top: filters.top || 100,
87+
sort: filters.sort || []
88+
};
89+
90+
return driver.find(object, ast, options);
91+
}
92+
93+
async insert(object: string, data: Record<string, any>, options?: DriverOptions) {
94+
const driver = this.getDriver(object);
95+
console.log(`[ObjectQL] Creating ${object} on ${driver.name}...`);
96+
// 1. Validate Schema
97+
// 2. Run "Before Insert" Triggers
98+
99+
const result = await driver.create(object, data, options);
100+
101+
// 3. Run "After Insert" Triggers
102+
return result;
103+
}
104+
105+
async update(object: string, id: string, data: Record<string, any>, options?: DriverOptions) {
106+
const driver = this.getDriver(object);
107+
console.log(`[ObjectQL] Updating ${object} ${id}...`);
108+
return driver.update(object, id, data, options);
109+
}
110+
111+
async delete(object: string, id: string, options?: DriverOptions) {
112+
const driver = this.getDriver(object);
113+
console.log(`[ObjectQL] Deleting ${object} ${id}...`);
114+
return driver.delete(object, id, options);
115+
}
116+
}

examples/objectql/src/index.ts

Lines changed: 4 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,5 @@
1-
import { DriverInterface, DriverOptions, QueryAST } from '@objectstack/spec';
1+
// Export core engine
2+
export { ObjectQL } from './engine';
23

3-
/**
4-
* ObjectQL Engine
5-
*
6-
* The core orchestration layer that sits between the API/UI and the Data Driver.
7-
* It handles:
8-
* 1. Request Validation (using Schemas)
9-
* 2. Security Enforcement (ACLs, Sharing Rules)
10-
* 3. Workflow Triggers
11-
* 4. Driver Delegation
12-
*/
13-
export class ObjectQL {
14-
private drivers = new Map<string, DriverInterface>();
15-
private defaultDriver: string | null = null;
16-
17-
constructor() {
18-
console.log(`[ObjectQL] Engine Instance Created`);
19-
}
20-
21-
/**
22-
* Register a new storage driver
23-
*/
24-
registerDriver(driver: DriverInterface, isDefault: boolean = false) {
25-
if (this.drivers.has(driver.name)) {
26-
console.warn(`[ObjectQL] Driver ${driver.name} is already registered. Skipping.`);
27-
return;
28-
}
29-
30-
this.drivers.set(driver.name, driver);
31-
console.log(`[ObjectQL] Registered driver: ${driver.name} v${driver.version}`);
32-
33-
if (isDefault || this.drivers.size === 1) {
34-
this.defaultDriver = driver.name;
35-
}
36-
}
37-
38-
/**
39-
* Helper to get the target driver
40-
*/
41-
private getDriver(object: string): DriverInterface {
42-
// TODO: Look up Object definition to see if it specifies a specific datasource/driver
43-
// For now, always return default
44-
if (!this.defaultDriver) {
45-
throw new Error('[ObjectQL] No drivers registered!');
46-
}
47-
return this.drivers.get(this.defaultDriver)!;
48-
}
49-
50-
/**
51-
* Initialize the engine and all registered drivers
52-
*/
53-
async init() {
54-
console.log('[ObjectQL] Initializing drivers...');
55-
for (const [name, driver] of this.drivers) {
56-
try {
57-
await driver.connect();
58-
} catch (e) {
59-
console.error(`[ObjectQL] Failed to connect driver ${name}`, e);
60-
}
61-
}
62-
// In a real app, we would sync schemas here
63-
}
64-
65-
async destroy() {
66-
for (const driver of this.drivers.values()) {
67-
await driver.disconnect();
68-
}
69-
}
70-
71-
// ============================================
72-
// Data Access Methods
73-
// ============================================
74-
75-
async find(object: string, filters: any = {}, options?: DriverOptions) {
76-
const driver = this.getDriver(object);
77-
console.log(`[ObjectQL] Finding ${object} on ${driver.name}...`);
78-
79-
// Transform simplified filters to QueryAST
80-
// This is a simplified "Mock" transform.
81-
// Real implementation would parse complex JSON or FilterBuilders.
82-
const ast: QueryAST = {
83-
// Pass through if it looks like AST, otherwise empty
84-
// In this demo, we assume the caller passes a simplified object or raw AST
85-
filters: filters.filters || undefined,
86-
top: filters.top || 100,
87-
sort: filters.sort || []
88-
};
89-
90-
return driver.find(object, ast, options);
91-
}
92-
93-
async insert(object: string, data: Record<string, any>, options?: DriverOptions) {
94-
const driver = this.getDriver(object);
95-
console.log(`[ObjectQL] Creating ${object} on ${driver.name}...`);
96-
// 1. Validate Schema
97-
// 2. Run "Before Insert" Triggers
98-
99-
const result = await driver.create(object, data, options);
100-
101-
// 3. Run "After Insert" Triggers
102-
return result;
103-
}
104-
105-
async update(object: string, id: string, data: Record<string, any>, options?: DriverOptions) {
106-
const driver = this.getDriver(object);
107-
console.log(`[ObjectQL] Updating ${object} ${id}...`);
108-
return driver.update(object, id, data, options);
109-
}
110-
111-
async delete(object: string, id: string, options?: DriverOptions) {
112-
const driver = this.getDriver(object);
113-
console.log(`[ObjectQL] Deleting ${object} ${id}...`);
114-
return driver.delete(object, id, options);
115-
}
116-
}
4+
// Re-export common types from spec for convenience
5+
export type { DriverInterface, DriverOptions, QueryAST } from '@objectstack/spec';

examples/server/src/kernel/engine.ts

Lines changed: 16 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -3,97 +3,52 @@ import { SchemaRegistry } from './registry';
33
import { InMemoryDriver } from '@objectstack/plugin-driver-memory';
44
import { ObjectQL } from '@objectstack/objectql';
55

6+
/**
7+
* Server Data Engine Wrapper
8+
*
9+
* This class is now a thin wrapper that initializes the ObjectQL Engine
10+
* with the appropriate Server-Side configuration (Registry, Drivers).
11+
*
12+
* The core logic has been moved to @objectstack/objectql.
13+
*/
614
export class DataEngine {
7-
private ql: ObjectQL;
15+
public ql: ObjectQL;
816

917
constructor() {
1018
this.ql = new ObjectQL();
1119

12-
// 1. Initialize Driver (Usually loaded from plugins or config)
20+
// 1. Initialize Driver
1321
const memoryDriver = new InMemoryDriver();
22+
this.ql.registerDriver(memoryDriver, true);
1423

15-
// 2. Register Driver to Engine
16-
this.ql.registerDriver(memoryDriver, true); // Set as default
17-
18-
// 3. Start Engine
24+
// 2. Start Engine
1925
this.ql.init().catch(console.error);
2026

21-
// Seed some data for demo
2227
this.seed();
2328
}
2429

2530
async seed() {
2631
await this.ql.insert('SystemStatus', { status: 'OK', uptime: 0 });
2732
}
2833

34+
// Forward methods to ObjectQL
2935
async find(objectName: string, query: any) {
3036
this.ensureSchema(objectName);
31-
32-
// Delegate to ObjectQL
3337
const results = await this.ql.find(objectName, { top: 100 });
34-
35-
return {
36-
value: results,
37-
count: results.length
38-
};
38+
return { value: results, count: results.length };
3939
}
4040

4141
async get(objectName: string, id: string) {
4242
this.ensureSchema(objectName);
43-
// Find One not fully implemented in engine wrapper yet, using find as mock
44-
const results = await this.ql.find(objectName, { top: 1 });
43+
// Find One
44+
const results = await this.ql.find(objectName, { top: 1 }); // Mock implementation
4545
return results[0];
4646
}
4747

4848
async create(objectName: string, data: any) {
4949
this.ensureSchema(objectName);
5050
return this.ql.insert(objectName, data);
5151
}
52-
const records = MEMORY_DB[objectName] || [];
53-
const record = records.find(r => r._id === id);
54-
if (!record) throw new Error(`Record not found: ${id}`);
55-
return record;
56-
}
57-
58-
async create(objectName: string, payload: any) {
59-
const schema = this.ensureSchema(objectName);
60-
61-
// Auto-generate ID and Timestamps
62-
const record = {
63-
_id: Math.random().toString(36).substring(7),
64-
created_at: new Date().toISOString(),
65-
...payload
66-
};
67-
68-
// TODO: Validate against schema.fields
69-
70-
if (!MEMORY_DB[objectName]) MEMORY_DB[objectName] = [];
71-
MEMORY_DB[objectName].push(record);
72-
73-
return record;
74-
}
75-
76-
async update(objectName: string, id: string, payload: any) {
77-
this.ensureSchema(objectName);
78-
const records = MEMORY_DB[objectName] || [];
79-
const index = records.findIndex(r => r._id === id);
80-
81-
if (index === -1) throw new Error(`Record not found: ${id}`);
82-
83-
records[index] = { ...records[index], ...payload, updated_at: new Date().toISOString() };
84-
return records[index];
85-
}
86-
87-
async delete(objectName: string, id: string) {
88-
this.ensureSchema(objectName);
89-
const records = MEMORY_DB[objectName] || [];
90-
const index = records.findIndex(r => r._id === id);
91-
92-
if (index === -1) throw new Error(`Record not found: ${id}`);
93-
94-
records.splice(index, 1);
95-
return { success: true };
96-
}
9752

9853
private ensureSchema(name: string): ServiceObject {
9954
const schema = SchemaRegistry.getObject(name);

0 commit comments

Comments
 (0)