@deessejs/collections 0.0.1

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.
@@ -0,0 +1,808 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { eq, and, like, gt, gte, lt, lte, isNull, inArray, not, desc, asc } from 'drizzle-orm'
3
+
4
+ import type { Collection, CollectionHooks, CreateHookContext, UpdateHookContext, DeleteHookContext, ReadHookContext, OperationHookContext } from '../collection'
5
+ import type {
6
+ FindManyOptions,
7
+ FindUniqueOptions,
8
+ FindFirstOptions,
9
+ CreateOptions,
10
+ CreateManyOptions,
11
+ UpdateOptions,
12
+ UpdateManyOptions,
13
+ DeleteOptions,
14
+ DeleteManyOptions,
15
+ CountOptions,
16
+ ExistsOptions,
17
+ WhereOperator
18
+ } from './types'
19
+
20
+ /**
21
+ * Collection operations interface
22
+ */
23
+ export interface CollectionOperations {
24
+ findMany<T>(options?: FindManyOptions): Promise<T[]>
25
+ findUnique<T>(options: FindUniqueOptions): Promise<T | undefined>
26
+ findFirst<T>(options: FindFirstOptions): Promise<T | undefined>
27
+ create<T>(options: CreateOptions<T>): Promise<T | undefined>
28
+ createMany<T>(options: CreateManyOptions<T>): Promise<number>
29
+ update<T>(options: UpdateOptions<T>): Promise<T | undefined>
30
+ updateMany<T>(options: UpdateManyOptions<T>): Promise<number>
31
+ delete<T>(options: DeleteOptions): Promise<T | undefined>
32
+ deleteMany(options: DeleteManyOptions): Promise<number>
33
+ count(options?: CountOptions): Promise<number>
34
+ exists(options: ExistsOptions): Promise<boolean>
35
+ }
36
+
37
+ /**
38
+ * Build where conditions from options
39
+ */
40
+ const buildWhereClause = (
41
+ tableColumns: Record<string, any>,
42
+ where?: Record<string, unknown>
43
+ ): any => {
44
+ if (!where) return undefined
45
+
46
+ const conditions: any[] = []
47
+
48
+ for (const [key, value] of Object.entries(where)) {
49
+ const column = tableColumns[key]
50
+ if (!column) continue
51
+
52
+ if (value === null || typeof value !== 'object') {
53
+ conditions.push(eq(column, value))
54
+ } else {
55
+ const operator = value as WhereOperator<unknown>
56
+ if ('eq' in operator) {
57
+ conditions.push(eq(column, operator.eq))
58
+ } else if ('neq' in operator) {
59
+ conditions.push(not(eq(column, operator.neq)))
60
+ } else if ('gt' in operator) {
61
+ conditions.push(gt(column, operator.gt as number))
62
+ } else if ('gte' in operator) {
63
+ conditions.push(gte(column, operator.gte as number))
64
+ } else if ('lt' in operator) {
65
+ conditions.push(lt(column, operator.lt as number))
66
+ } else if ('lte' in operator) {
67
+ conditions.push(lte(column, operator.lte as number))
68
+ } else if ('in' in operator) {
69
+ conditions.push(inArray(column, operator.in))
70
+ } else if ('notIn' in operator) {
71
+ conditions.push(not(inArray(column, operator.notIn)))
72
+ } else if ('contains' in operator) {
73
+ conditions.push(like(column, `%${operator.contains}%`))
74
+ } else if ('startsWith' in operator) {
75
+ conditions.push(like(column, `${operator.startsWith}%`))
76
+ } else if ('endsWith' in operator) {
77
+ conditions.push(like(column, `%${operator.endsWith}`))
78
+ } else if ('isNull' in operator) {
79
+ if (operator.isNull) {
80
+ conditions.push(isNull(column))
81
+ }
82
+ } else if ('not' in operator) {
83
+ conditions.push(not(eq(column, operator.not)))
84
+ }
85
+ }
86
+ }
87
+
88
+ if (conditions.length === 0) return undefined
89
+ if (conditions.length === 1) return conditions[0]
90
+ return and(...conditions)
91
+ }
92
+
93
+ /**
94
+ * Build orderBy from options
95
+ */
96
+ const buildOrderBy = (
97
+ tableColumns: Record<string, any>,
98
+ orderBy?: Record<string, unknown> | Record<string, unknown>[]
99
+ ): any[] => {
100
+ if (!orderBy) return []
101
+
102
+ const orders = Array.isArray(orderBy) ? orderBy : [orderBy]
103
+ return orders.map((order) => {
104
+ for (const [key, direction] of Object.entries(order)) {
105
+ const column = tableColumns[key]
106
+ if (!column) continue
107
+ return direction === 'desc' ? desc(column) : asc(column)
108
+ }
109
+ return undefined
110
+ }).filter(Boolean)
111
+ }
112
+
113
+ /**
114
+ * Execute before operation hooks
115
+ */
116
+ const executeBeforeOperationHooks = async (
117
+ hooks: CollectionHooks | undefined,
118
+ context: OperationHookContext
119
+ ): Promise<void> => {
120
+ if (!hooks?.beforeOperation) return
121
+ for (const hook of hooks.beforeOperation) {
122
+ await hook(context)
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Execute after operation hooks
128
+ */
129
+ const executeAfterOperationHooks = async (
130
+ hooks: CollectionHooks | undefined,
131
+ context: OperationHookContext
132
+ ): Promise<void> => {
133
+ if (!hooks?.afterOperation) return
134
+ for (const hook of hooks.afterOperation) {
135
+ await hook(context)
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Execute before create hooks
141
+ */
142
+ const executeBeforeCreateHooks = async (
143
+ hooks: CollectionHooks | undefined,
144
+ context: CreateHookContext
145
+ ): Promise<void> => {
146
+ if (!hooks?.beforeCreate) return
147
+ for (const hook of hooks.beforeCreate) {
148
+ await hook(context)
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Execute after create hooks
154
+ */
155
+ const executeAfterCreateHooks = async (
156
+ hooks: CollectionHooks | undefined,
157
+ context: CreateHookContext
158
+ ): Promise<void> => {
159
+ if (!hooks?.afterCreate) return
160
+ for (const hook of hooks.afterCreate) {
161
+ await hook(context)
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Execute before update hooks
167
+ */
168
+ const executeBeforeUpdateHooks = async (
169
+ hooks: CollectionHooks | undefined,
170
+ context: UpdateHookContext
171
+ ): Promise<void> => {
172
+ if (!hooks?.beforeUpdate) return
173
+ for (const hook of hooks.beforeUpdate) {
174
+ await hook(context)
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Execute after update hooks
180
+ */
181
+ const executeAfterUpdateHooks = async (
182
+ hooks: CollectionHooks | undefined,
183
+ context: UpdateHookContext
184
+ ): Promise<void> => {
185
+ if (!hooks?.afterUpdate) return
186
+ for (const hook of hooks.afterUpdate) {
187
+ await hook(context)
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Execute before delete hooks
193
+ */
194
+ const executeBeforeDeleteHooks = async (
195
+ hooks: CollectionHooks | undefined,
196
+ context: DeleteHookContext
197
+ ): Promise<void> => {
198
+ if (!hooks?.beforeDelete) return
199
+ for (const hook of hooks.beforeDelete) {
200
+ await hook(context)
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Execute after delete hooks
206
+ */
207
+ const executeAfterDeleteHooks = async (
208
+ hooks: CollectionHooks | undefined,
209
+ context: DeleteHookContext
210
+ ): Promise<void> => {
211
+ if (!hooks?.afterDelete) return
212
+ for (const hook of hooks.afterDelete) {
213
+ await hook(context)
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Execute before read hooks
219
+ */
220
+ const executeBeforeReadHooks = async (
221
+ hooks: CollectionHooks | undefined,
222
+ context: ReadHookContext
223
+ ): Promise<void> => {
224
+ if (!hooks?.beforeRead) return
225
+ for (const hook of hooks.beforeRead) {
226
+ await hook(context)
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Execute after read hooks
232
+ */
233
+ const executeAfterReadHooks = async (
234
+ hooks: CollectionHooks | undefined,
235
+ context: ReadHookContext
236
+ ): Promise<void> => {
237
+ if (!hooks?.afterRead) return
238
+ for (const hook of hooks.afterRead) {
239
+ await hook(context)
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Creates collection operations with Drizzle
245
+ */
246
+ export const createCollectionOperations = (
247
+ _collection: Collection,
248
+ _slug: string,
249
+ _db: any,
250
+ _table: any,
251
+ _hooks?: CollectionHooks
252
+ ): CollectionOperations => {
253
+ const tableColumns = _table as Record<string, any>
254
+ const db = _db as any
255
+ const hooks = _hooks as CollectionHooks | undefined
256
+
257
+ // If no db instance, return placeholder operations
258
+ if (!db) {
259
+ return {
260
+ findMany: async <T>(): Promise<T[]> => [],
261
+ findUnique: async <T>(): Promise<T | undefined> => undefined,
262
+ findFirst: async <T>(): Promise<T | undefined> => undefined,
263
+ create: async <T>(): Promise<T | undefined> => undefined,
264
+ createMany: async (): Promise<number> => 0,
265
+ update: async <T>(): Promise<T | undefined> => undefined,
266
+ updateMany: async (): Promise<number> => 0,
267
+ delete: async <T>(): Promise<T | undefined> => undefined,
268
+ deleteMany: async (): Promise<number> => 0,
269
+ count: async (): Promise<number> => 0,
270
+ exists: async (): Promise<boolean> => false
271
+ }
272
+ }
273
+
274
+ return {
275
+ findMany: async <T>(options?: FindManyOptions): Promise<T[]> => {
276
+ const whereClause = buildWhereClause(tableColumns, options?.where)
277
+ const orderByClause = buildOrderBy(tableColumns, options?.orderBy)
278
+
279
+ // Execute before operation hooks
280
+ await executeBeforeOperationHooks(hooks, {
281
+ collection: _slug,
282
+ operation: 'read',
283
+ where: options?.where
284
+ })
285
+
286
+ // Execute before read hooks
287
+ await executeBeforeReadHooks(hooks, {
288
+ collection: _slug,
289
+ operation: 'read',
290
+ query: options as unknown as Record<string, unknown>,
291
+ db
292
+ })
293
+
294
+ let query = db.select().from(_table)
295
+
296
+ if (whereClause) {
297
+ query = query.where(whereClause)
298
+ }
299
+
300
+ if (orderByClause.length > 0) {
301
+ query = query.orderBy(...orderByClause)
302
+ }
303
+
304
+ if (options?.offset) {
305
+ query = query.offset(options.offset)
306
+ }
307
+
308
+ if (options?.limit) {
309
+ query = query.limit(options.limit)
310
+ }
311
+
312
+ const result = await query
313
+
314
+ // Execute after read hooks
315
+ await executeAfterReadHooks(hooks, {
316
+ collection: _slug,
317
+ operation: 'read',
318
+ query: options as unknown as Record<string, unknown>,
319
+ result: result as unknown[],
320
+ db
321
+ })
322
+
323
+ // Execute after operation hooks
324
+ await executeAfterOperationHooks(hooks, {
325
+ collection: _slug,
326
+ operation: 'read',
327
+ where: options?.where,
328
+ result
329
+ })
330
+
331
+ return result as T[]
332
+ },
333
+
334
+ findUnique: async <T>(options: FindUniqueOptions): Promise<T | undefined> => {
335
+ const whereClause = buildWhereClause(tableColumns, options.where)
336
+ if (!whereClause) return undefined
337
+
338
+ // Execute before operation hooks
339
+ await executeBeforeOperationHooks(hooks, {
340
+ collection: _slug,
341
+ operation: 'read',
342
+ where: options.where
343
+ })
344
+
345
+ // Execute before read hooks
346
+ await executeBeforeReadHooks(hooks, {
347
+ collection: _slug,
348
+ operation: 'read',
349
+ query: options as unknown as Record<string, unknown>,
350
+ db
351
+ })
352
+
353
+ const result = await db.select().from(_table).where(whereClause).limit(1)
354
+ const returnValue = result[0] as T | undefined
355
+
356
+ // Execute after read hooks
357
+ await executeAfterReadHooks(hooks, {
358
+ collection: _slug,
359
+ operation: 'read',
360
+ query: options as unknown as Record<string, unknown>,
361
+ result: returnValue ? [returnValue] : [],
362
+ db
363
+ })
364
+
365
+ // Execute after operation hooks
366
+ await executeAfterOperationHooks(hooks, {
367
+ collection: _slug,
368
+ operation: 'read',
369
+ where: options.where,
370
+ result: returnValue
371
+ })
372
+
373
+ return returnValue
374
+ },
375
+
376
+ findFirst: async <T>(options: FindFirstOptions): Promise<T | undefined> => {
377
+ const whereClause = buildWhereClause(tableColumns, options.where)
378
+ const orderByClause = buildOrderBy(tableColumns, options.orderBy)
379
+
380
+ // Execute before operation hooks
381
+ await executeBeforeOperationHooks(hooks, {
382
+ collection: _slug,
383
+ operation: 'read',
384
+ where: options.where
385
+ })
386
+
387
+ // Execute before read hooks
388
+ await executeBeforeReadHooks(hooks, {
389
+ collection: _slug,
390
+ operation: 'read',
391
+ query: options as unknown as Record<string, unknown>,
392
+ db
393
+ })
394
+
395
+ let query = db.select().from(_table)
396
+
397
+ if (whereClause) {
398
+ query = query.where(whereClause)
399
+ }
400
+
401
+ if (orderByClause.length > 0) {
402
+ query = query.orderBy(...orderByClause)
403
+ }
404
+
405
+ const result = await query.limit(1)
406
+ const returnValue = result[0] as T | undefined
407
+
408
+ // Execute after read hooks
409
+ await executeAfterReadHooks(hooks, {
410
+ collection: _slug,
411
+ operation: 'read',
412
+ query: options as unknown as Record<string, unknown>,
413
+ result: returnValue ? [returnValue] : [],
414
+ db
415
+ })
416
+
417
+ // Execute after operation hooks
418
+ await executeAfterOperationHooks(hooks, {
419
+ collection: _slug,
420
+ operation: 'read',
421
+ where: options.where,
422
+ result: returnValue
423
+ })
424
+
425
+ return returnValue
426
+ },
427
+
428
+ create: async <T>(options: CreateOptions<T>): Promise<T | undefined> => {
429
+ const data = Array.isArray(options.data) ? options.data : [options.data]
430
+ const firstData = data[0] as Record<string, unknown>
431
+
432
+ // Execute before operation hooks
433
+ await executeBeforeOperationHooks(hooks, {
434
+ collection: _slug,
435
+ operation: 'create',
436
+ data: firstData,
437
+ where: undefined
438
+ })
439
+
440
+ // Execute before create hooks
441
+ await executeBeforeCreateHooks(hooks, {
442
+ collection: _slug,
443
+ operation: 'create',
444
+ data: firstData,
445
+ db
446
+ })
447
+
448
+ const result = await db.insert(_table).values(data).returning()
449
+
450
+ const returnValue = options.returning ? result[0] as T : undefined
451
+
452
+ // Execute after create hooks
453
+ await executeAfterCreateHooks(hooks, {
454
+ collection: _slug,
455
+ operation: 'create',
456
+ data: firstData,
457
+ result: returnValue,
458
+ db
459
+ })
460
+
461
+ // Execute after operation hooks
462
+ await executeAfterOperationHooks(hooks, {
463
+ collection: _slug,
464
+ operation: 'create',
465
+ data: firstData,
466
+ result: returnValue
467
+ })
468
+
469
+ return returnValue
470
+ },
471
+
472
+ createMany: async <T>(options: CreateManyOptions<T>): Promise<number> => {
473
+ const dataArray = Array.isArray(options.data) ? options.data : [options.data]
474
+
475
+ // Execute before operation hooks for each item
476
+ for (const data of dataArray) {
477
+ await executeBeforeOperationHooks(hooks, {
478
+ collection: _slug,
479
+ operation: 'create',
480
+ data: data as Record<string, unknown>,
481
+ where: undefined
482
+ })
483
+
484
+ await executeBeforeCreateHooks(hooks, {
485
+ collection: _slug,
486
+ operation: 'create',
487
+ data: data as Record<string, unknown>,
488
+ db
489
+ })
490
+ }
491
+
492
+ const result = await db.insert(_table).values(options.data as any)
493
+
494
+ // Execute after operation hooks for each item
495
+ for (let i = 0; i < dataArray.length; i++) {
496
+ await executeAfterCreateHooks(hooks, {
497
+ collection: _slug,
498
+ operation: 'create',
499
+ data: dataArray[i] as Record<string, unknown>,
500
+ result: result[i],
501
+ db
502
+ })
503
+
504
+ await executeAfterOperationHooks(hooks, {
505
+ collection: _slug,
506
+ operation: 'create',
507
+ data: dataArray[i] as Record<string, unknown>,
508
+ result: result[i]
509
+ })
510
+ }
511
+
512
+ return result.length || 0
513
+ },
514
+
515
+ update: async <T>(options: UpdateOptions<T>): Promise<T | undefined> => {
516
+ const whereClause = buildWhereClause(tableColumns, options.where)
517
+ if (!whereClause) return undefined
518
+
519
+ // Get previous data for hooks
520
+ const previousResult = await db.select().from(_table).where(whereClause).limit(1)
521
+ const previousData = previousResult[0] as Record<string, unknown> | undefined
522
+
523
+ // Execute before operation hooks
524
+ await executeBeforeOperationHooks(hooks, {
525
+ collection: _slug,
526
+ operation: 'update',
527
+ data: options.data as Record<string, unknown>,
528
+ where: options.where
529
+ })
530
+
531
+ // Execute before update hooks
532
+ await executeBeforeUpdateHooks(hooks, {
533
+ collection: _slug,
534
+ operation: 'update',
535
+ data: options.data as Record<string, unknown>,
536
+ where: options.where,
537
+ previousData,
538
+ db
539
+ })
540
+
541
+ const result = await db.update(_table)
542
+ .set(options.data as any)
543
+ .where(whereClause)
544
+ .returning()
545
+
546
+ const returnValue = options.returning ? result[0] as T : undefined
547
+
548
+ // Execute after update hooks
549
+ await executeAfterUpdateHooks(hooks, {
550
+ collection: _slug,
551
+ operation: 'update',
552
+ data: options.data as Record<string, unknown>,
553
+ where: options.where,
554
+ previousData,
555
+ result: returnValue,
556
+ db
557
+ })
558
+
559
+ // Execute after operation hooks
560
+ await executeAfterOperationHooks(hooks, {
561
+ collection: _slug,
562
+ operation: 'update',
563
+ data: options.data as Record<string, unknown>,
564
+ where: options.where,
565
+ result: returnValue
566
+ })
567
+
568
+ return returnValue
569
+ },
570
+
571
+ updateMany: async <T>(options: UpdateManyOptions<T>): Promise<number> => {
572
+ const whereClause = buildWhereClause(tableColumns, options.where)
573
+ if (!whereClause) return 0
574
+
575
+ // Get previous data for hooks
576
+ const previousResults = await db.select().from(_table).where(whereClause)
577
+
578
+ // Execute before operation hooks
579
+ await executeBeforeOperationHooks(hooks, {
580
+ collection: _slug,
581
+ operation: 'update',
582
+ data: options.data as Record<string, unknown>,
583
+ where: options.where
584
+ })
585
+
586
+ // Execute before update hooks (for each previous record)
587
+ for (const previousData of previousResults) {
588
+ await executeBeforeUpdateHooks(hooks, {
589
+ collection: _slug,
590
+ operation: 'update',
591
+ data: options.data as Record<string, unknown>,
592
+ where: options.where,
593
+ previousData: previousData as Record<string, unknown>,
594
+ db
595
+ })
596
+ }
597
+
598
+ const result = await db.update(_table)
599
+ .set(options.data as any)
600
+ .where(whereClause)
601
+
602
+ // Execute after update hooks
603
+ for (const previousData of previousResults) {
604
+ await executeAfterUpdateHooks(hooks, {
605
+ collection: _slug,
606
+ operation: 'update',
607
+ data: options.data as Record<string, unknown>,
608
+ where: options.where,
609
+ previousData: previousData as Record<string, unknown>,
610
+ db
611
+ })
612
+ }
613
+
614
+ // Execute after operation hooks
615
+ await executeAfterOperationHooks(hooks, {
616
+ collection: _slug,
617
+ operation: 'update',
618
+ data: options.data as Record<string, unknown>,
619
+ where: options.where
620
+ })
621
+
622
+ return result.length || 0
623
+ },
624
+
625
+ delete: async <T>(options: DeleteOptions): Promise<T | undefined> => {
626
+ const whereClause = buildWhereClause(tableColumns, options.where)
627
+ if (!whereClause) return undefined
628
+
629
+ // Get previous data for hooks
630
+ const previousResult = await db.select().from(_table).where(whereClause).limit(1)
631
+ const previousData = previousResult[0] as Record<string, unknown> | undefined
632
+
633
+ // Execute before operation hooks
634
+ await executeBeforeOperationHooks(hooks, {
635
+ collection: _slug,
636
+ operation: 'delete',
637
+ where: options.where
638
+ })
639
+
640
+ // Execute before delete hooks
641
+ await executeBeforeDeleteHooks(hooks, {
642
+ collection: _slug,
643
+ operation: 'delete',
644
+ where: options.where,
645
+ previousData,
646
+ db
647
+ })
648
+
649
+ const result = await db.delete(_table)
650
+ .where(whereClause)
651
+ .returning()
652
+
653
+ const returnValue = options.returning ? result[0] as T : undefined
654
+
655
+ // Execute after delete hooks
656
+ await executeAfterDeleteHooks(hooks, {
657
+ collection: _slug,
658
+ operation: 'delete',
659
+ where: options.where,
660
+ previousData,
661
+ result: returnValue,
662
+ db
663
+ })
664
+
665
+ // Execute after operation hooks
666
+ await executeAfterOperationHooks(hooks, {
667
+ collection: _slug,
668
+ operation: 'delete',
669
+ where: options.where,
670
+ result: returnValue
671
+ })
672
+
673
+ return returnValue
674
+ },
675
+
676
+ deleteMany: async (options: DeleteManyOptions): Promise<number> => {
677
+ const whereClause = buildWhereClause(tableColumns, options.where)
678
+ if (!whereClause) return 0
679
+
680
+ // Get previous data for hooks
681
+ const previousResults = await db.select().from(_table).where(whereClause)
682
+
683
+ // Execute before operation hooks
684
+ await executeBeforeOperationHooks(hooks, {
685
+ collection: _slug,
686
+ operation: 'delete',
687
+ where: options.where
688
+ })
689
+
690
+ // Execute before delete hooks
691
+ for (const previousData of previousResults) {
692
+ await executeBeforeDeleteHooks(hooks, {
693
+ collection: _slug,
694
+ operation: 'delete',
695
+ where: options.where,
696
+ previousData: previousData as Record<string, unknown>,
697
+ db
698
+ })
699
+ }
700
+
701
+ const result = await db.delete(_table).where(whereClause)
702
+
703
+ // Execute after delete hooks
704
+ for (const previousData of previousResults) {
705
+ await executeAfterDeleteHooks(hooks, {
706
+ collection: _slug,
707
+ operation: 'delete',
708
+ where: options.where,
709
+ previousData: previousData as Record<string, unknown>,
710
+ db
711
+ })
712
+ }
713
+
714
+ // Execute after operation hooks
715
+ await executeAfterOperationHooks(hooks, {
716
+ collection: _slug,
717
+ operation: 'delete',
718
+ where: options.where
719
+ })
720
+
721
+ return result.length || 0
722
+ },
723
+
724
+ count: async (options?: CountOptions): Promise<number> => {
725
+ const whereClause = buildWhereClause(tableColumns, options?.where)
726
+
727
+ // Execute before operation hooks
728
+ await executeBeforeOperationHooks(hooks, {
729
+ collection: _slug,
730
+ operation: 'read',
731
+ where: options?.where
732
+ })
733
+
734
+ // Execute before read hooks
735
+ await executeBeforeReadHooks(hooks, {
736
+ collection: _slug,
737
+ operation: 'read',
738
+ query: options as unknown as Record<string, unknown>,
739
+ db
740
+ })
741
+
742
+ const result = whereClause
743
+ ? await db.select().from(_table).where(whereClause)
744
+ : await db.select().from(_table)
745
+
746
+ // Execute after read hooks
747
+ await executeAfterReadHooks(hooks, {
748
+ collection: _slug,
749
+ operation: 'read',
750
+ query: options as unknown as Record<string, unknown>,
751
+ result,
752
+ db
753
+ })
754
+
755
+ // Execute after operation hooks
756
+ await executeAfterOperationHooks(hooks, {
757
+ collection: _slug,
758
+ operation: 'read',
759
+ where: options?.where,
760
+ result
761
+ })
762
+
763
+ return result.length
764
+ },
765
+
766
+ exists: async (options: ExistsOptions): Promise<boolean> => {
767
+ const whereClause = buildWhereClause(tableColumns, options.where)
768
+ if (!whereClause) return false
769
+
770
+ // Execute before operation hooks
771
+ await executeBeforeOperationHooks(hooks, {
772
+ collection: _slug,
773
+ operation: 'read',
774
+ where: options.where
775
+ })
776
+
777
+ // Execute before read hooks
778
+ await executeBeforeReadHooks(hooks, {
779
+ collection: _slug,
780
+ operation: 'read',
781
+ query: options as unknown as Record<string, unknown>,
782
+ db
783
+ })
784
+
785
+ const result = await db.select().from(_table).where(whereClause).limit(1)
786
+ const returnValue = result.length > 0
787
+
788
+ // Execute after read hooks
789
+ await executeAfterReadHooks(hooks, {
790
+ collection: _slug,
791
+ operation: 'read',
792
+ query: options as unknown as Record<string, unknown>,
793
+ result: result,
794
+ db
795
+ })
796
+
797
+ // Execute after operation hooks
798
+ await executeAfterOperationHooks(hooks, {
799
+ collection: _slug,
800
+ operation: 'read',
801
+ where: options.where,
802
+ result: returnValue
803
+ })
804
+
805
+ return returnValue
806
+ }
807
+ }
808
+ }