@@ -6,6 +6,20 @@ import { SchemaRegistry } from './registry';
66// Export Registry for consumers
77export { SchemaRegistry } from './registry' ;
88
9+ /**
10+ * Hook Context
11+ */
12+ export interface HookContext {
13+ object : string ;
14+ driver : DriverInterface ;
15+ method : 'find' | 'insert' | 'update' | 'delete' | 'count' ;
16+ args : any ; // The arguments passed to the method (can be modified)
17+ result ?: any ; // The result of the operation (for after hooks)
18+ error ?: any ; // The error if one occurred (for error hooks)
19+ }
20+
21+ export type HookHandler = ( context : HookContext ) => Promise < void > | void ;
22+
923/**
1024 * Host Context provided to plugins
1125 */
@@ -23,6 +37,14 @@ export class ObjectQL {
2337 private drivers = new Map < string , DriverInterface > ( ) ;
2438 private defaultDriver : string | null = null ;
2539
40+ // Hooks Registry
41+ private hooks : Record < string , HookHandler [ ] > = {
42+ 'beforeFind' : [ ] , 'afterFind' : [ ] ,
43+ 'beforeInsert' : [ ] , 'afterInsert' : [ ] ,
44+ 'beforeUpdate' : [ ] , 'afterUpdate' : [ ] ,
45+ 'beforeDelete' : [ ] , 'afterDelete' : [ ] ,
46+ } ;
47+
2648 // Host provided context additions (e.g. Server router)
2749 private hostContext : Record < string , any > = { } ;
2850
@@ -94,6 +116,27 @@ export class ObjectQL {
94116 }
95117 }
96118
119+ /**
120+ * Register a hook
121+ * @param event The event name (e.g. 'beforeFind', 'afterInsert')
122+ * @param handler The handler function
123+ */
124+ registerHook ( event : string , handler : HookHandler ) {
125+ if ( ! this . hooks [ event ] ) {
126+ this . hooks [ event ] = [ ] ;
127+ }
128+ this . hooks [ event ] . push ( handler ) ;
129+ console . log ( `[ObjectQL] Registered hook for ${ event } ` ) ;
130+ }
131+
132+ private async triggerHooks ( event : string , context : HookContext ) {
133+ const handlers = this . hooks [ event ] || [ ] ;
134+ for ( const handler of handlers ) {
135+ // In a real system, we might want to catch errors here or allow them to bubble up
136+ await handler ( context ) ;
137+ }
138+ }
139+
97140 /**
98141 * Register a new storage driver
99142 */
@@ -189,27 +232,35 @@ export class ObjectQL {
189232 // Normalize QueryAST
190233 let ast : QueryAST ;
191234 if ( query . where || query . fields || query . orderBy || query . limit ) {
192- // It's likely a QueryAST or partial QueryAST
193- // Ensure 'object' is set correctly
194- ast = {
195- object, // Force object name to match the call
196- ...query
197- } as QueryAST ;
235+ ast = { object, ...query } as QueryAST ;
198236 } else {
199- // It's a direct filter object (Simplified syntax)
200- // e.g. find('account', { name: 'Acme' })
201- ast = {
202- object,
203- where : query
204- } as QueryAST ;
237+ ast = { object, where : query } as QueryAST ;
205238 }
206239
207- // Default limit protection
208- if ( ast . limit === undefined ) {
209- ast . limit = 100 ;
210- }
240+ if ( ast . limit === undefined ) ast . limit = 100 ;
211241
212- return driver . find ( object , ast , options ) ;
242+ // Trigger Before Hook
243+ const hookContext : HookContext = {
244+ object,
245+ driver,
246+ method : 'find' ,
247+ args : { ast, options } // Hooks can modify AST here
248+ } ;
249+ await this . triggerHooks ( 'beforeFind' , hookContext ) ;
250+
251+ try {
252+ const result = await driver . find ( object , hookContext . args . ast , hookContext . args . options ) ;
253+
254+ // Trigger After Hook
255+ hookContext . result = result ;
256+ await this . triggerHooks ( 'afterFind' , hookContext ) ;
257+
258+ return hookContext . result ;
259+ } catch ( e ) {
260+ hookContext . error = e ;
261+ // await this.triggerHooks('error', hookContext);
262+ throw e ;
263+ }
213264 }
214265
215266 async findOne ( object : string , idOrQuery : string | any , options ?: DriverOptions ) {
@@ -247,21 +298,60 @@ export class ObjectQL {
247298 // validate(schema, data);
248299 }
249300
250- // 2. Run "Before Insert" Triggers
301+ // 2. Trigger Before Hook
302+ const hookContext : HookContext = {
303+ object,
304+ driver,
305+ method : 'insert' ,
306+ args : { data, options }
307+ } ;
308+ await this . triggerHooks ( 'beforeInsert' , hookContext ) ;
251309
252- const result = await driver . create ( object , data , options ) ;
310+ // 3. Execute Driver
311+ const result = await driver . create ( object , hookContext . args . data , hookContext . args . options ) ;
253312
254- // 3. Run "After Insert" Triggers
255- return result ;
313+ // 4. Trigger After Hook
314+ hookContext . result = result ;
315+ await this . triggerHooks ( 'afterInsert' , hookContext ) ;
316+
317+ return hookContext . result ;
256318 }
257319
258320 async update ( object : string , id : string | number , data : Record < string , any > , options ?: DriverOptions ) {
259321 const driver = this . getDriver ( object ) ;
260- return driver . update ( object , id , data , options ) ;
322+
323+ const hookContext : HookContext = {
324+ object,
325+ driver,
326+ method : 'update' ,
327+ args : { id, data, options }
328+ } ;
329+ await this . triggerHooks ( 'beforeUpdate' , hookContext ) ;
330+
331+ const result = await driver . update ( object , hookContext . args . id , hookContext . args . data , hookContext . args . options ) ;
332+
333+ hookContext . result = result ;
334+ await this . triggerHooks ( 'afterUpdate' , hookContext ) ;
335+
336+ return hookContext . result ;
261337 }
262338
263339 async delete ( object : string , id : string | number , options ?: DriverOptions ) {
264340 const driver = this . getDriver ( object ) ;
265- return driver . delete ( object , id , options ) ;
341+
342+ const hookContext : HookContext = {
343+ object,
344+ driver,
345+ method : 'delete' ,
346+ args : { id, options }
347+ } ;
348+ await this . triggerHooks ( 'beforeDelete' , hookContext ) ;
349+
350+ const result = await driver . delete ( object , hookContext . args . id , hookContext . args . options ) ;
351+
352+ hookContext . result = result ;
353+ await this . triggerHooks ( 'afterDelete' , hookContext ) ;
354+
355+ return hookContext . result ;
266356 }
267357}
0 commit comments