@plyaz/db 0.4.0 → 0.5.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.mjs CHANGED
@@ -7180,6 +7180,1201 @@ async function createDatabaseService(config) {
7180
7180
  }
7181
7181
  __name(createDatabaseService, "createDatabaseService");
7182
7182
 
7183
+ // src/builder/query/QueryBuilder.ts
7184
+ var QueryBuilder = class _QueryBuilder {
7185
+ static {
7186
+ __name(this, "QueryBuilder");
7187
+ }
7188
+ _filters = [];
7189
+ _rawConditions = [];
7190
+ _sort = [];
7191
+ _pagination = {};
7192
+ _schema;
7193
+ _executor;
7194
+ _operationConfig;
7195
+ _countExecutor;
7196
+ // Advanced query features
7197
+ _joins = [];
7198
+ _groupByFields = [];
7199
+ _havingConditions = [];
7200
+ _selectFields = [];
7201
+ _selectRawExpressions = [];
7202
+ _distinct = false;
7203
+ /**
7204
+ * Create a new QueryBuilder instance (standalone)
7205
+ *
7206
+ * @returns New QueryBuilder instance
7207
+ *
7208
+ * @example
7209
+ * ```typescript
7210
+ * const builder = QueryBuilder.create<User>();
7211
+ * ```
7212
+ */
7213
+ static create() {
7214
+ return new _QueryBuilder();
7215
+ }
7216
+ /**
7217
+ * Create a QueryBuilder bound to a repository for direct execution
7218
+ *
7219
+ * @param executor - Repository or object with findMany method
7220
+ * @returns New QueryBuilder instance bound to executor
7221
+ *
7222
+ * @example
7223
+ * ```typescript
7224
+ * // Usually called via repository.query()
7225
+ * const builder = QueryBuilder.forRepository(userRepository);
7226
+ * const result = await builder.where('status', 'eq', 'active').execute();
7227
+ * ```
7228
+ */
7229
+ static forRepository(executor) {
7230
+ const builder = new _QueryBuilder();
7231
+ builder._executor = executor;
7232
+ return builder;
7233
+ }
7234
+ /**
7235
+ * Private constructor - use QueryBuilder.create() or forRepository() instead
7236
+ */
7237
+ constructor() {
7238
+ }
7239
+ /**
7240
+ * Add a WHERE condition with AND logical operator
7241
+ *
7242
+ * @param field - Field name to filter on
7243
+ * @param operator - Comparison operator
7244
+ * @param value - Value to compare against
7245
+ * @returns This builder for chaining
7246
+ *
7247
+ * @example
7248
+ * ```typescript
7249
+ * builder.where('status', 'eq', 'active')
7250
+ * ```
7251
+ */
7252
+ where(field, operator, value) {
7253
+ this._filters.push({
7254
+ field,
7255
+ operator,
7256
+ value,
7257
+ logical: this._filters.length === 0 ? void 0 : "and"
7258
+ });
7259
+ return this;
7260
+ }
7261
+ /**
7262
+ * Add a WHERE condition with explicit AND logical operator
7263
+ *
7264
+ * @param field - Field name to filter on
7265
+ * @param operator - Comparison operator
7266
+ * @param value - Value to compare against
7267
+ * @returns This builder for chaining
7268
+ *
7269
+ * @example
7270
+ * ```typescript
7271
+ * builder.where('status', 'eq', 'active')
7272
+ * .andWhere('role', 'eq', 'admin')
7273
+ * ```
7274
+ */
7275
+ andWhere(field, operator, value) {
7276
+ this._filters.push({
7277
+ field,
7278
+ operator,
7279
+ value,
7280
+ logical: "and"
7281
+ });
7282
+ return this;
7283
+ }
7284
+ /**
7285
+ * Add a WHERE condition with OR logical operator
7286
+ *
7287
+ * @param field - Field name to filter on
7288
+ * @param operator - Comparison operator
7289
+ * @param value - Value to compare against
7290
+ * @returns This builder for chaining
7291
+ *
7292
+ * @example
7293
+ * ```typescript
7294
+ * builder.where('status', 'eq', 'active')
7295
+ * .orWhere('status', 'eq', 'pending')
7296
+ * ```
7297
+ */
7298
+ orWhere(field, operator, value) {
7299
+ this._filters.push({
7300
+ field,
7301
+ operator,
7302
+ value,
7303
+ logical: "or"
7304
+ });
7305
+ return this;
7306
+ }
7307
+ /**
7308
+ * Add a WHERE IN condition
7309
+ *
7310
+ * @param field - Field name to filter on
7311
+ * @param values - Array of values to match
7312
+ * @returns This builder for chaining
7313
+ *
7314
+ * @example
7315
+ * ```typescript
7316
+ * builder.whereIn('status', ['active', 'pending', 'review'])
7317
+ * ```
7318
+ */
7319
+ whereIn(field, values) {
7320
+ this._filters.push({
7321
+ field,
7322
+ operator: "in",
7323
+ value: values,
7324
+ logical: this._filters.length === 0 ? void 0 : "and"
7325
+ });
7326
+ return this;
7327
+ }
7328
+ /**
7329
+ * Add a WHERE NOT IN condition
7330
+ *
7331
+ * @param field - Field name to filter on
7332
+ * @param values - Array of values to exclude
7333
+ * @returns This builder for chaining
7334
+ *
7335
+ * @example
7336
+ * ```typescript
7337
+ * builder.whereNotIn('status', ['deleted', 'archived'])
7338
+ * ```
7339
+ */
7340
+ whereNotIn(field, values) {
7341
+ this._filters.push({
7342
+ field,
7343
+ operator: "notIn",
7344
+ value: values,
7345
+ logical: this._filters.length === 0 ? void 0 : "and"
7346
+ });
7347
+ return this;
7348
+ }
7349
+ /**
7350
+ * Add a WHERE BETWEEN condition
7351
+ *
7352
+ * @param field - Field name to filter on
7353
+ * @param min - Minimum value (inclusive)
7354
+ * @param max - Maximum value (inclusive)
7355
+ * @returns This builder for chaining
7356
+ *
7357
+ * @example
7358
+ * ```typescript
7359
+ * builder.whereBetween('price', 10, 100)
7360
+ * builder.whereBetween('createdAt', startDate, endDate)
7361
+ * ```
7362
+ */
7363
+ whereBetween(field, min, max) {
7364
+ this._filters.push({
7365
+ field,
7366
+ operator: "between",
7367
+ value: [min, max],
7368
+ logical: this._filters.length === 0 ? void 0 : "and"
7369
+ });
7370
+ return this;
7371
+ }
7372
+ /**
7373
+ * Add a WHERE LIKE condition (pattern matching)
7374
+ *
7375
+ * @param field - Field name to filter on
7376
+ * @param pattern - LIKE pattern (use % for wildcards)
7377
+ * @returns This builder for chaining
7378
+ *
7379
+ * @example
7380
+ * ```typescript
7381
+ * builder.whereLike('email', '%@example.com')
7382
+ * builder.whereLike('name', 'John%')
7383
+ * ```
7384
+ */
7385
+ whereLike(field, pattern) {
7386
+ this._filters.push({
7387
+ field,
7388
+ operator: "like",
7389
+ value: pattern,
7390
+ logical: this._filters.length === 0 ? void 0 : "and"
7391
+ });
7392
+ return this;
7393
+ }
7394
+ /**
7395
+ * Add a WHERE IS NULL condition
7396
+ *
7397
+ * @param field - Field name to check for NULL
7398
+ * @returns This builder for chaining
7399
+ *
7400
+ * @example
7401
+ * ```typescript
7402
+ * builder.whereNull('deletedAt')
7403
+ * ```
7404
+ */
7405
+ whereNull(field) {
7406
+ this._filters.push({
7407
+ field,
7408
+ operator: "isNull",
7409
+ value: null,
7410
+ logical: this._filters.length === 0 ? void 0 : "and"
7411
+ });
7412
+ return this;
7413
+ }
7414
+ /**
7415
+ * Add a WHERE IS NOT NULL condition
7416
+ *
7417
+ * @param field - Field name to check for non-NULL
7418
+ * @returns This builder for chaining
7419
+ *
7420
+ * @example
7421
+ * ```typescript
7422
+ * builder.whereNotNull('verifiedAt')
7423
+ * ```
7424
+ */
7425
+ whereNotNull(field) {
7426
+ this._filters.push({
7427
+ field,
7428
+ operator: "isNotNull",
7429
+ value: null,
7430
+ logical: this._filters.length === 0 ? void 0 : "and"
7431
+ });
7432
+ return this;
7433
+ }
7434
+ /**
7435
+ * Add a raw SQL WHERE condition for complex queries
7436
+ *
7437
+ * Use this for conditions that cannot be expressed with the standard operators,
7438
+ * such as subqueries, JSON operations, full-text search, or database-specific functions.
7439
+ *
7440
+ * @param clause - Raw SQL clause (use $1, $2, etc. for parameter placeholders)
7441
+ * @param params - Parameter values for the clause (prevents SQL injection)
7442
+ * @returns This builder for chaining
7443
+ *
7444
+ * @example
7445
+ * ```typescript
7446
+ * // JSON field query (PostgreSQL)
7447
+ * builder.whereRaw('"metadata"->\'tags\' @> $1', [JSON.stringify(['featured'])])
7448
+ *
7449
+ * // Full-text search
7450
+ * builder.whereRaw('to_tsvector(name) @@ plainto_tsquery($1)', ['search term'])
7451
+ *
7452
+ * // Subquery
7453
+ * builder.whereRaw('"id" IN (SELECT user_id FROM orders WHERE total > $1)', [1000])
7454
+ *
7455
+ * // Date functions
7456
+ * builder.whereRaw('DATE_TRUNC(\'month\', "createdAt") = DATE_TRUNC(\'month\', $1)', [new Date()])
7457
+ *
7458
+ * // Complex conditions
7459
+ * builder
7460
+ * .where('status', 'eq', 'active')
7461
+ * .whereRaw('("score" > $1 OR "isPremium" = $2)', [80, true])
7462
+ * ```
7463
+ */
7464
+ whereRaw(clause, params = []) {
7465
+ const hasConditions = this._filters.length > 0 || this._rawConditions.length > 0;
7466
+ this._rawConditions.push({
7467
+ clause,
7468
+ params,
7469
+ logical: hasConditions ? "and" : void 0
7470
+ });
7471
+ return this;
7472
+ }
7473
+ /**
7474
+ * Add a raw SQL WHERE condition with OR logical operator
7475
+ *
7476
+ * @param clause - Raw SQL clause (use $1, $2, etc. for parameter placeholders)
7477
+ * @param params - Parameter values for the clause
7478
+ * @returns This builder for chaining
7479
+ *
7480
+ * @example
7481
+ * ```typescript
7482
+ * builder
7483
+ * .where('status', 'eq', 'active')
7484
+ * .orWhereRaw('"metadata"->\'priority\' = $1', ['"high"'])
7485
+ * ```
7486
+ */
7487
+ orWhereRaw(clause, params = []) {
7488
+ this._rawConditions.push({
7489
+ clause,
7490
+ params,
7491
+ logical: "or"
7492
+ });
7493
+ return this;
7494
+ }
7495
+ // ============================================================
7496
+ // SELECT Methods
7497
+ // ============================================================
7498
+ /**
7499
+ * Select specific fields (columns) to return
7500
+ *
7501
+ * @param fields - Field names to select
7502
+ * @returns This builder for chaining
7503
+ *
7504
+ * @example
7505
+ * ```typescript
7506
+ * builder.select('id', 'name', 'email')
7507
+ *
7508
+ * // With table prefix for joins
7509
+ * builder
7510
+ * .select('users.id', 'users.name', 'orders.total')
7511
+ * .leftJoin('orders', 'users.id = orders.user_id')
7512
+ * ```
7513
+ */
7514
+ select(...fields) {
7515
+ this._selectFields.push(...fields);
7516
+ return this;
7517
+ }
7518
+ /**
7519
+ * Add raw SELECT expression
7520
+ *
7521
+ * @param expression - Raw SQL expression
7522
+ * @returns This builder for chaining
7523
+ *
7524
+ * @example
7525
+ * ```typescript
7526
+ * builder
7527
+ * .select('id', 'name')
7528
+ * .selectRaw('COUNT(*) as order_count')
7529
+ * .selectRaw('SUM(orders.total) as total_spent')
7530
+ * ```
7531
+ */
7532
+ selectRaw(expression) {
7533
+ this._selectRawExpressions.push(expression);
7534
+ return this;
7535
+ }
7536
+ /**
7537
+ * Add DISTINCT to SELECT
7538
+ *
7539
+ * @returns This builder for chaining
7540
+ *
7541
+ * @example
7542
+ * ```typescript
7543
+ * builder
7544
+ * .distinct()
7545
+ * .select('category')
7546
+ * .orderBy('category', 'asc')
7547
+ * ```
7548
+ */
7549
+ distinct() {
7550
+ this._distinct = true;
7551
+ return this;
7552
+ }
7553
+ // ============================================================
7554
+ // JOIN Methods
7555
+ // ============================================================
7556
+ /**
7557
+ * Add INNER JOIN clause
7558
+ *
7559
+ * @param table - Table to join
7560
+ * @param condition - Join condition
7561
+ * @param alias - Optional alias for the joined table
7562
+ * @returns This builder for chaining
7563
+ *
7564
+ * @example
7565
+ * ```typescript
7566
+ * builder
7567
+ * .join('orders', 'users.id = orders.user_id')
7568
+ * .where('orders.status', 'eq', 'completed')
7569
+ *
7570
+ * // With alias
7571
+ * builder.join('orders', 'u.id = o.user_id', 'o')
7572
+ *
7573
+ * // With schema
7574
+ * builder.innerJoin('analytics.events', 'users.id = events.user_id')
7575
+ * ```
7576
+ */
7577
+ join(table, condition, alias) {
7578
+ return this.innerJoin(table, condition, alias);
7579
+ }
7580
+ /**
7581
+ * Add INNER JOIN clause (explicit)
7582
+ *
7583
+ * @param table - Table to join (can include schema: 'schema.table')
7584
+ * @param condition - Join condition
7585
+ * @param alias - Optional alias for the joined table
7586
+ * @returns This builder for chaining
7587
+ */
7588
+ innerJoin(table, condition, alias) {
7589
+ const [schema, tableName] = this.parseTableName(table);
7590
+ this._joins.push({
7591
+ type: "inner",
7592
+ table: tableName,
7593
+ condition,
7594
+ alias,
7595
+ schema
7596
+ });
7597
+ return this;
7598
+ }
7599
+ /**
7600
+ * Add LEFT JOIN clause
7601
+ *
7602
+ * @param table - Table to join (can include schema: 'schema.table')
7603
+ * @param condition - Join condition
7604
+ * @param alias - Optional alias for the joined table
7605
+ * @returns This builder for chaining
7606
+ *
7607
+ * @example
7608
+ * ```typescript
7609
+ * builder
7610
+ * .leftJoin('orders', 'users.id = orders.user_id')
7611
+ * .select('users.*', 'orders.total')
7612
+ * ```
7613
+ */
7614
+ leftJoin(table, condition, alias) {
7615
+ const [schema, tableName] = this.parseTableName(table);
7616
+ this._joins.push({
7617
+ type: "left",
7618
+ table: tableName,
7619
+ condition,
7620
+ alias,
7621
+ schema
7622
+ });
7623
+ return this;
7624
+ }
7625
+ /**
7626
+ * Add RIGHT JOIN clause
7627
+ *
7628
+ * @param table - Table to join (can include schema: 'schema.table')
7629
+ * @param condition - Join condition
7630
+ * @param alias - Optional alias for the joined table
7631
+ * @returns This builder for chaining
7632
+ */
7633
+ rightJoin(table, condition, alias) {
7634
+ const [schema, tableName] = this.parseTableName(table);
7635
+ this._joins.push({
7636
+ type: "right",
7637
+ table: tableName,
7638
+ condition,
7639
+ alias,
7640
+ schema
7641
+ });
7642
+ return this;
7643
+ }
7644
+ /**
7645
+ * Add FULL OUTER JOIN clause
7646
+ *
7647
+ * @param table - Table to join (can include schema: 'schema.table')
7648
+ * @param condition - Join condition
7649
+ * @param alias - Optional alias for the joined table
7650
+ * @returns This builder for chaining
7651
+ */
7652
+ fullJoin(table, condition, alias) {
7653
+ const [schema, tableName] = this.parseTableName(table);
7654
+ this._joins.push({
7655
+ type: "full",
7656
+ table: tableName,
7657
+ condition,
7658
+ alias,
7659
+ schema
7660
+ });
7661
+ return this;
7662
+ }
7663
+ /**
7664
+ * Parse table name that may include schema (schema.table)
7665
+ */
7666
+ parseTableName(table) {
7667
+ const SCHEMA_TABLE_PARTS = 2;
7668
+ const parts = table.split(".");
7669
+ if (parts.length === SCHEMA_TABLE_PARTS) {
7670
+ return [parts[0], parts[1]];
7671
+ }
7672
+ return [void 0, table];
7673
+ }
7674
+ // ============================================================
7675
+ // GROUP BY / HAVING Methods
7676
+ // ============================================================
7677
+ /**
7678
+ * Add GROUP BY clause
7679
+ *
7680
+ * @param fields - Fields to group by
7681
+ * @returns This builder for chaining
7682
+ *
7683
+ * @example
7684
+ * ```typescript
7685
+ * builder
7686
+ * .select('status')
7687
+ * .selectRaw('COUNT(*) as count')
7688
+ * .groupBy('status')
7689
+ *
7690
+ * // Multiple fields
7691
+ * builder
7692
+ * .select('region', 'status')
7693
+ * .selectRaw('SUM(amount) as total')
7694
+ * .groupBy('region', 'status')
7695
+ * ```
7696
+ */
7697
+ groupBy(...fields) {
7698
+ this._groupByFields.push(...fields);
7699
+ return this;
7700
+ }
7701
+ /**
7702
+ * Add HAVING condition (for use with GROUP BY)
7703
+ *
7704
+ * @param clause - Raw SQL HAVING condition (use $1, $2 for params)
7705
+ * @param params - Parameter values
7706
+ * @returns This builder for chaining
7707
+ *
7708
+ * @example
7709
+ * ```typescript
7710
+ * builder
7711
+ * .select('status')
7712
+ * .selectRaw('COUNT(*) as count')
7713
+ * .groupBy('status')
7714
+ * .having('COUNT(*) > $1', [10])
7715
+ *
7716
+ * // Multiple having conditions
7717
+ * builder
7718
+ * .groupBy('category')
7719
+ * .selectRaw('AVG(price) as avg_price')
7720
+ * .having('AVG(price) > $1', [100])
7721
+ * .having('COUNT(*) >= $1', [5])
7722
+ * ```
7723
+ */
7724
+ having(clause, params = []) {
7725
+ this._havingConditions.push({
7726
+ clause,
7727
+ params,
7728
+ logical: this._havingConditions.length === 0 ? void 0 : "and"
7729
+ });
7730
+ return this;
7731
+ }
7732
+ /**
7733
+ * Add HAVING condition with OR
7734
+ *
7735
+ * @param clause - Raw SQL HAVING condition
7736
+ * @param params - Parameter values
7737
+ * @returns This builder for chaining
7738
+ */
7739
+ orHaving(clause, params = []) {
7740
+ this._havingConditions.push({
7741
+ clause,
7742
+ params,
7743
+ logical: "or"
7744
+ });
7745
+ return this;
7746
+ }
7747
+ /**
7748
+ * Add ORDER BY clause
7749
+ *
7750
+ * @param field - Field name to sort by
7751
+ * @param direction - Sort direction ('asc' or 'desc')
7752
+ * @returns This builder for chaining
7753
+ *
7754
+ * @example
7755
+ * ```typescript
7756
+ * builder.orderBy('createdAt', 'desc')
7757
+ * ```
7758
+ */
7759
+ orderBy(field, direction = "asc") {
7760
+ this._sort.push({ field, direction });
7761
+ return this;
7762
+ }
7763
+ /**
7764
+ * Add ORDER BY ASC clause (convenience method)
7765
+ *
7766
+ * @param field - Field name to sort by ascending
7767
+ * @returns This builder for chaining
7768
+ *
7769
+ * @example
7770
+ * ```typescript
7771
+ * builder.orderByAsc('name')
7772
+ * ```
7773
+ */
7774
+ orderByAsc(field) {
7775
+ return this.orderBy(field, "asc");
7776
+ }
7777
+ /**
7778
+ * Add ORDER BY DESC clause (convenience method)
7779
+ *
7780
+ * @param field - Field name to sort by descending
7781
+ * @returns This builder for chaining
7782
+ *
7783
+ * @example
7784
+ * ```typescript
7785
+ * builder.orderByDesc('createdAt')
7786
+ * ```
7787
+ */
7788
+ orderByDesc(field) {
7789
+ return this.orderBy(field, "desc");
7790
+ }
7791
+ /**
7792
+ * Set LIMIT for results
7793
+ *
7794
+ * @param limit - Maximum number of results to return
7795
+ * @returns This builder for chaining
7796
+ *
7797
+ * @example
7798
+ * ```typescript
7799
+ * builder.limit(20)
7800
+ * ```
7801
+ */
7802
+ limit(limit) {
7803
+ this._pagination.limit = limit;
7804
+ return this;
7805
+ }
7806
+ /**
7807
+ * Set OFFSET for results
7808
+ *
7809
+ * @param offset - Number of results to skip
7810
+ * @returns This builder for chaining
7811
+ *
7812
+ * @example
7813
+ * ```typescript
7814
+ * builder.offset(40)
7815
+ * ```
7816
+ */
7817
+ offset(offset) {
7818
+ this._pagination.offset = offset;
7819
+ return this;
7820
+ }
7821
+ /**
7822
+ * Set pagination by page number
7823
+ *
7824
+ * @param page - Page number (1-indexed)
7825
+ * @param pageSize - Number of items per page
7826
+ * @returns This builder for chaining
7827
+ *
7828
+ * @example
7829
+ * ```typescript
7830
+ * builder.paginate(2, 25) // Page 2, 25 items per page
7831
+ * ```
7832
+ */
7833
+ paginate(page, pageSize) {
7834
+ this._pagination.limit = pageSize;
7835
+ this._pagination.offset = (page - 1) * pageSize;
7836
+ return this;
7837
+ }
7838
+ /**
7839
+ * Set cursor for cursor-based pagination
7840
+ *
7841
+ * @param cursor - Cursor string from previous query
7842
+ * @returns This builder for chaining
7843
+ *
7844
+ * @example
7845
+ * ```typescript
7846
+ * builder.afterCursor('eyJpZCI6MTIzfQ==')
7847
+ * ```
7848
+ */
7849
+ afterCursor(cursor) {
7850
+ this._pagination.cursor = cursor;
7851
+ return this;
7852
+ }
7853
+ /**
7854
+ * Set database schema
7855
+ *
7856
+ * @param schema - Schema name to query from
7857
+ * @returns This builder for chaining
7858
+ *
7859
+ * @example
7860
+ * ```typescript
7861
+ * builder.schema('analytics')
7862
+ * ```
7863
+ */
7864
+ schema(schema) {
7865
+ this._schema = schema;
7866
+ return this;
7867
+ }
7868
+ /**
7869
+ * Set operation config for execute()
7870
+ *
7871
+ * @param config - Operation configuration (adapter, schema override, etc.)
7872
+ * @returns This builder for chaining
7873
+ *
7874
+ * @example
7875
+ * ```typescript
7876
+ * const result = await userRepository.query()
7877
+ * .where('status', 'eq', 'active')
7878
+ * .withConfig({ adapter: 'analytics' })
7879
+ * .execute();
7880
+ * ```
7881
+ */
7882
+ withConfig(config) {
7883
+ this._operationConfig = config;
7884
+ return this;
7885
+ }
7886
+ /**
7887
+ * Execute the query using the bound repository
7888
+ *
7889
+ * Requires QueryBuilder to be created via repository.query() or forRepository()
7890
+ *
7891
+ * @returns Promise resolving to paginated results
7892
+ * @throws Error if no executor is bound
7893
+ *
7894
+ * @example
7895
+ * ```typescript
7896
+ * const result = await userRepository.query()
7897
+ * .where('status', 'eq', 'active')
7898
+ * .orderByDesc('createdAt')
7899
+ * .limit(20)
7900
+ * .execute();
7901
+ *
7902
+ * if (result.success) {
7903
+ * console.log('Found users:', result.value.data);
7904
+ * }
7905
+ * ```
7906
+ */
7907
+ async execute() {
7908
+ if (!this._executor) {
7909
+ throw new Error(
7910
+ "QueryBuilder has no executor. Use repository.query() or QueryBuilder.forRepository() to enable execute()."
7911
+ );
7912
+ }
7913
+ return this._executor.findMany(this.build(), this._operationConfig);
7914
+ }
7915
+ /**
7916
+ * Execute and return just the data array (convenience method)
7917
+ *
7918
+ * @returns Promise resolving to array of records
7919
+ * @throws Error if query fails or no executor
7920
+ *
7921
+ * @example
7922
+ * ```typescript
7923
+ * const users = await userRepository.query()
7924
+ * .where('status', 'eq', 'active')
7925
+ * .getMany();
7926
+ * ```
7927
+ */
7928
+ async getMany() {
7929
+ const result = await this.execute();
7930
+ if (!result.success || !result.value) {
7931
+ throw result.error ?? new Error("Query failed");
7932
+ }
7933
+ return result.value.data;
7934
+ }
7935
+ /**
7936
+ * Execute and return the first result (convenience method)
7937
+ *
7938
+ * @returns Promise resolving to first record or null
7939
+ * @throws Error if query fails or no executor
7940
+ *
7941
+ * @example
7942
+ * ```typescript
7943
+ * const user = await userRepository.query()
7944
+ * .where('email', 'eq', 'john@example.com')
7945
+ * .getOne();
7946
+ * ```
7947
+ */
7948
+ async getOne() {
7949
+ const originalLimit = this._pagination.limit;
7950
+ this._pagination.limit = 1;
7951
+ const result = await this.execute();
7952
+ this._pagination.limit = originalLimit;
7953
+ if (!result.success || !result.value) {
7954
+ throw result.error ?? new Error("Query failed");
7955
+ }
7956
+ return result.value.data[0] ?? null;
7957
+ }
7958
+ /**
7959
+ * Execute a count query
7960
+ *
7961
+ * Returns the count of records matching the filter conditions.
7962
+ * Requires QueryBuilder to be created via repository.query() or forRepository()
7963
+ *
7964
+ * @returns Promise resolving to the count
7965
+ * @throws Error if no executor or count not supported
7966
+ *
7967
+ * @example
7968
+ * ```typescript
7969
+ * const count = await userRepository.query()
7970
+ * .where('status', 'eq', 'active')
7971
+ * .count();
7972
+ *
7973
+ * // Complex count
7974
+ * const premiumCount = await userRepository.query()
7975
+ * .where('role', 'eq', 'premium')
7976
+ * .andWhere('verified', 'eq', true)
7977
+ * .count();
7978
+ * ```
7979
+ */
7980
+ async count() {
7981
+ if (!this._executor) {
7982
+ throw new Error(
7983
+ "QueryBuilder has no executor. Use repository.query() to enable count()."
7984
+ );
7985
+ }
7986
+ if (!this._executor.count) {
7987
+ throw new Error("Executor does not support count().");
7988
+ }
7989
+ const filter = this._filters.length > 0 ? this._filters[0] : void 0;
7990
+ const result = await this._executor.count(filter, this._operationConfig);
7991
+ if (!result.success) {
7992
+ throw result.error ?? new Error("Count query failed");
7993
+ }
7994
+ return result.value ?? 0;
7995
+ }
7996
+ /**
7997
+ * Check if any records exist matching the conditions
7998
+ *
7999
+ * @returns Promise resolving to true if at least one record exists
8000
+ * @throws Error if query fails or no executor
8001
+ *
8002
+ * @example
8003
+ * ```typescript
8004
+ * const hasActiveUsers = await userRepository.query()
8005
+ * .where('status', 'eq', 'active')
8006
+ * .exists();
8007
+ * ```
8008
+ */
8009
+ async exists() {
8010
+ const count = await this.count();
8011
+ return count > 0;
8012
+ }
8013
+ /**
8014
+ * Build QueryOptions for BaseRepository.findMany()
8015
+ *
8016
+ * For single filter queries, returns standard QueryOptions.
8017
+ * For multi-filter queries, returns the first filter (use toFilters() for full array).
8018
+ *
8019
+ * @returns QueryOptions compatible with BaseRepository
8020
+ *
8021
+ * @example
8022
+ * ```typescript
8023
+ * const options = builder.build();
8024
+ * const result = await repository.findMany(options);
8025
+ * ```
8026
+ */
8027
+ build() {
8028
+ const options = {};
8029
+ if (this._filters.length > 0) {
8030
+ options.filter = this._filters[0];
8031
+ }
8032
+ if (this._sort.length > 0) {
8033
+ options.sort = this._sort;
8034
+ }
8035
+ if (this._pagination.limit !== void 0 || this._pagination.offset !== void 0 || this._pagination.cursor !== void 0) {
8036
+ options.pagination = this._pagination;
8037
+ }
8038
+ if (this._schema) {
8039
+ options.schema = this._schema;
8040
+ }
8041
+ return options;
8042
+ }
8043
+ /**
8044
+ * Build and return full result including filters array and raw conditions
8045
+ *
8046
+ * Use this when you need access to all filters for direct SQL building
8047
+ * or when using multi-condition queries with raw SQL.
8048
+ *
8049
+ * @returns QueryBuilderResult with options, filters, and raw conditions
8050
+ *
8051
+ * @example
8052
+ * ```typescript
8053
+ * const { options, filters, rawConditions } = builder.buildFull();
8054
+ *
8055
+ * // Use options for repository
8056
+ * const result = await repository.findMany(options);
8057
+ *
8058
+ * // Use filters for custom SQL building
8059
+ * const whereClause = buildWhereClause(filters);
8060
+ *
8061
+ * // Append raw conditions manually
8062
+ * rawConditions.forEach(raw => {
8063
+ * whereClause += ` ${raw.logical?.toUpperCase() ?? ''} ${raw.clause}`;
8064
+ * });
8065
+ * ```
8066
+ */
8067
+ buildFull() {
8068
+ const result = {
8069
+ options: this.build(),
8070
+ filters: [...this._filters],
8071
+ rawConditions: [...this._rawConditions],
8072
+ joins: [...this._joins]
8073
+ };
8074
+ if (this._groupByFields.length > 0) {
8075
+ result.groupBy = {
8076
+ fields: [...this._groupByFields],
8077
+ having: this._havingConditions.length > 0 ? this._havingConditions.map((h) => ({ ...h })) : void 0
8078
+ };
8079
+ }
8080
+ if (this._selectFields.length > 0 || this._selectRawExpressions.length > 0 || this._distinct) {
8081
+ result.select = {
8082
+ fields: [...this._selectFields],
8083
+ rawExpressions: [...this._selectRawExpressions],
8084
+ distinct: this._distinct
8085
+ };
8086
+ }
8087
+ return result;
8088
+ }
8089
+ /**
8090
+ * Get array of all filters
8091
+ *
8092
+ * Use for direct SQL building with buildWhereClause()
8093
+ *
8094
+ * @returns Array of Filter objects
8095
+ *
8096
+ * @example
8097
+ * ```typescript
8098
+ * const filters = builder.toFilters();
8099
+ * const whereClause = buildWhereClause(filters);
8100
+ * ```
8101
+ */
8102
+ toFilters() {
8103
+ return [...this._filters];
8104
+ }
8105
+ /**
8106
+ * Get array of raw SQL conditions
8107
+ *
8108
+ * Use for manual SQL building with complex conditions
8109
+ *
8110
+ * @returns Array of RawCondition objects
8111
+ *
8112
+ * @example
8113
+ * ```typescript
8114
+ * const rawConditions = builder.toRawConditions();
8115
+ * // Manually append to WHERE clause
8116
+ * ```
8117
+ */
8118
+ toRawConditions() {
8119
+ return [...this._rawConditions];
8120
+ }
8121
+ /**
8122
+ * Get array of sort options
8123
+ *
8124
+ * @returns Array of SortOptions
8125
+ */
8126
+ toSortOptions() {
8127
+ return [...this._sort];
8128
+ }
8129
+ /**
8130
+ * Get pagination options
8131
+ *
8132
+ * @returns PaginationOptions
8133
+ */
8134
+ toPaginationOptions() {
8135
+ return { ...this._pagination };
8136
+ }
8137
+ /**
8138
+ * Check if any filters are defined (standard or raw)
8139
+ *
8140
+ * @returns True if filters exist
8141
+ */
8142
+ hasFilters() {
8143
+ return this._filters.length > 0 || this._rawConditions.length > 0;
8144
+ }
8145
+ /**
8146
+ * Check if raw SQL conditions are defined
8147
+ *
8148
+ * @returns True if raw conditions exist
8149
+ */
8150
+ hasRawConditions() {
8151
+ return this._rawConditions.length > 0;
8152
+ }
8153
+ /**
8154
+ * Check if sorting is defined
8155
+ *
8156
+ * @returns True if sort options exist
8157
+ */
8158
+ hasSort() {
8159
+ return this._sort.length > 0;
8160
+ }
8161
+ /**
8162
+ * Check if pagination is defined
8163
+ *
8164
+ * @returns True if pagination options exist
8165
+ */
8166
+ hasPagination() {
8167
+ return this._pagination.limit !== void 0 || this._pagination.offset !== void 0 || this._pagination.cursor !== void 0;
8168
+ }
8169
+ /**
8170
+ * Reset all query parameters
8171
+ *
8172
+ * @returns This builder for chaining
8173
+ */
8174
+ reset() {
8175
+ this._filters = [];
8176
+ this._rawConditions = [];
8177
+ this._sort = [];
8178
+ this._pagination = {};
8179
+ this._schema = void 0;
8180
+ this._operationConfig = void 0;
8181
+ this._joins = [];
8182
+ this._groupByFields = [];
8183
+ this._havingConditions = [];
8184
+ this._selectFields = [];
8185
+ this._selectRawExpressions = [];
8186
+ this._distinct = false;
8187
+ return this;
8188
+ }
8189
+ /**
8190
+ * Clone this query builder
8191
+ *
8192
+ * @returns New QueryBuilder with same parameters
8193
+ *
8194
+ * @example
8195
+ * ```typescript
8196
+ * const baseQuery = QueryBuilder.create<User>()
8197
+ * .where('status', 'eq', 'active');
8198
+ *
8199
+ * const adminQuery = baseQuery.clone()
8200
+ * .andWhere('role', 'eq', 'admin');
8201
+ *
8202
+ * const userQuery = baseQuery.clone()
8203
+ * .andWhere('role', 'eq', 'user');
8204
+ * ```
8205
+ */
8206
+ clone() {
8207
+ const cloned = new _QueryBuilder();
8208
+ cloned._filters = [...this._filters];
8209
+ cloned._rawConditions = this._rawConditions.map((rc) => ({ ...rc }));
8210
+ cloned._sort = [...this._sort];
8211
+ cloned._pagination = { ...this._pagination };
8212
+ cloned._schema = this._schema;
8213
+ cloned._executor = this._executor;
8214
+ cloned._operationConfig = this._operationConfig ? { ...this._operationConfig } : void 0;
8215
+ cloned._joins = this._joins.map((j) => ({ ...j }));
8216
+ cloned._groupByFields = [...this._groupByFields];
8217
+ cloned._havingConditions = this._havingConditions.map((h) => ({ ...h }));
8218
+ cloned._selectFields = [...this._selectFields];
8219
+ cloned._selectRawExpressions = [...this._selectRawExpressions];
8220
+ cloned._distinct = this._distinct;
8221
+ return cloned;
8222
+ }
8223
+ // ============================================================
8224
+ // Additional Helper Methods
8225
+ // ============================================================
8226
+ /**
8227
+ * Check if JOINs are defined
8228
+ *
8229
+ * @returns True if joins exist
8230
+ */
8231
+ hasJoins() {
8232
+ return this._joins.length > 0;
8233
+ }
8234
+ /**
8235
+ * Check if GROUP BY is defined
8236
+ *
8237
+ * @returns True if group by fields exist
8238
+ */
8239
+ hasGroupBy() {
8240
+ return this._groupByFields.length > 0;
8241
+ }
8242
+ /**
8243
+ * Check if custom SELECT is defined
8244
+ *
8245
+ * @returns True if select fields or expressions exist
8246
+ */
8247
+ hasSelect() {
8248
+ return this._selectFields.length > 0 || this._selectRawExpressions.length > 0 || this._distinct;
8249
+ }
8250
+ /**
8251
+ * Get JOIN clauses
8252
+ *
8253
+ * @returns Array of JoinClause objects
8254
+ */
8255
+ toJoins() {
8256
+ return [...this._joins];
8257
+ }
8258
+ /**
8259
+ * Get GROUP BY fields
8260
+ *
8261
+ * @returns Array of field names
8262
+ */
8263
+ toGroupByFields() {
8264
+ return [...this._groupByFields];
8265
+ }
8266
+ /**
8267
+ * Get HAVING conditions
8268
+ *
8269
+ * @returns Array of RawCondition objects
8270
+ */
8271
+ toHavingConditions() {
8272
+ return [...this._havingConditions];
8273
+ }
8274
+ /**
8275
+ * Get SELECT fields
8276
+ *
8277
+ * @returns Array of field names
8278
+ */
8279
+ toSelectFields() {
8280
+ return [...this._selectFields];
8281
+ }
8282
+ /**
8283
+ * Get SELECT raw expressions
8284
+ *
8285
+ * @returns Array of raw SQL expressions
8286
+ */
8287
+ toSelectRawExpressions() {
8288
+ return [...this._selectRawExpressions];
8289
+ }
8290
+ /**
8291
+ * Check if DISTINCT is enabled
8292
+ *
8293
+ * @returns True if distinct is enabled
8294
+ */
8295
+ isDistinct() {
8296
+ return this._distinct;
8297
+ }
8298
+ /**
8299
+ * Generate SQL query string (for debugging/logging)
8300
+ *
8301
+ * Note: This is a simplified SQL representation. The actual query
8302
+ * execution uses the adapter's SQL generation.
8303
+ *
8304
+ * @param tableName - Base table name
8305
+ * @returns SQL query string
8306
+ *
8307
+ * @example
8308
+ * ```typescript
8309
+ * const sql = builder
8310
+ * .select('id', 'name')
8311
+ * .leftJoin('orders', 'users.id = orders.user_id')
8312
+ * .where('status', 'eq', 'active')
8313
+ * .toSQL('users');
8314
+ *
8315
+ * console.log(sql);
8316
+ * // SELECT "id", "name" FROM "users"
8317
+ * // LEFT JOIN "orders" ON users.id = orders.user_id
8318
+ * // WHERE "status" = $1
8319
+ * ```
8320
+ */
8321
+ // eslint-disable-next-line complexity
8322
+ toSQL(tableName) {
8323
+ const parts = [];
8324
+ const selectParts = [];
8325
+ if (this._selectFields.length > 0) {
8326
+ selectParts.push(...this._selectFields.map((f) => `"${f}"`));
8327
+ }
8328
+ if (this._selectRawExpressions.length > 0) {
8329
+ selectParts.push(...this._selectRawExpressions);
8330
+ }
8331
+ const selectClause = selectParts.length > 0 ? selectParts.join(", ") : "*";
8332
+ parts.push(
8333
+ `SELECT ${this._distinct ? "DISTINCT " : ""}${selectClause} FROM "${tableName}"`
8334
+ );
8335
+ for (const join4 of this._joins) {
8336
+ const joinType = join4.type.toUpperCase();
8337
+ const tableRef = join4.schema ? `"${join4.schema}"."${join4.table}"` : `"${join4.table}"`;
8338
+ const aliasStr = join4.alias ? ` AS "${join4.alias}"` : "";
8339
+ parts.push(
8340
+ `${joinType} JOIN ${tableRef}${aliasStr} ON ${join4.condition}`
8341
+ );
8342
+ }
8343
+ if (this._filters.length > 0 || this._rawConditions.length > 0) {
8344
+ const whereParts = [];
8345
+ for (const filter of this._filters) {
8346
+ whereParts.push(`"${filter.field}" ${filter.operator} ?`);
8347
+ }
8348
+ for (const raw of this._rawConditions) {
8349
+ whereParts.push(raw.clause);
8350
+ }
8351
+ parts.push(`WHERE ${whereParts.join(" AND ")}`);
8352
+ }
8353
+ if (this._groupByFields.length > 0) {
8354
+ parts.push(
8355
+ `GROUP BY ${this._groupByFields.map((f) => `"${f}"`).join(", ")}`
8356
+ );
8357
+ }
8358
+ if (this._havingConditions.length > 0) {
8359
+ const havingParts = this._havingConditions.map((h) => h.clause);
8360
+ parts.push(`HAVING ${havingParts.join(" AND ")}`);
8361
+ }
8362
+ if (this._sort.length > 0) {
8363
+ const orderParts = this._sort.map(
8364
+ (s) => `"${s.field}" ${s.direction.toUpperCase()}`
8365
+ );
8366
+ parts.push(`ORDER BY ${orderParts.join(", ")}`);
8367
+ }
8368
+ if (this._pagination.limit !== void 0) {
8369
+ parts.push(`LIMIT ${this._pagination.limit}`);
8370
+ }
8371
+ if (this._pagination.offset !== void 0) {
8372
+ parts.push(`OFFSET ${this._pagination.offset}`);
8373
+ }
8374
+ return parts.join("\n");
8375
+ }
8376
+ };
8377
+
7183
8378
  // src/repository/BaseRepository.ts
7184
8379
  var BaseRepository = class {
7185
8380
  constructor(db, tableName, defaultConfig) {
@@ -7191,6 +8386,47 @@ var BaseRepository = class {
7191
8386
  __name(this, "BaseRepository");
7192
8387
  }
7193
8388
  defaultConfig;
8389
+ /**
8390
+ * Create a fluent QueryBuilder for this repository
8391
+ *
8392
+ * Returns a type-safe, chainable query builder that can execute queries
8393
+ * directly against this repository.
8394
+ *
8395
+ * @returns QueryBuilder bound to this repository
8396
+ *
8397
+ * @example
8398
+ * ```typescript
8399
+ * // Fluent query with execute
8400
+ * const result = await userRepository.query()
8401
+ * .where('status', 'eq', 'active')
8402
+ * .orderByDesc('createdAt')
8403
+ * .limit(20)
8404
+ * .execute();
8405
+ *
8406
+ * // Get data directly
8407
+ * const users = await userRepository.query()
8408
+ * .where('role', 'eq', 'admin')
8409
+ * .getMany();
8410
+ *
8411
+ * // Get single record
8412
+ * const user = await userRepository.query()
8413
+ * .where('email', 'eq', 'john@example.com')
8414
+ * .getOne();
8415
+ *
8416
+ * // Complex queries
8417
+ * const orders = await orderRepository.query()
8418
+ * .where('status', 'eq', 'pending')
8419
+ * .andWhere('totalAmount', 'gte', 100)
8420
+ * .orWhere('priority', 'eq', 'high')
8421
+ * .whereIn('region', ['US', 'EU'])
8422
+ * .orderBy('createdAt', 'desc')
8423
+ * .paginate(1, 25)
8424
+ * .execute();
8425
+ * ```
8426
+ */
8427
+ query() {
8428
+ return QueryBuilder.forRepository(this);
8429
+ }
7194
8430
  /**
7195
8431
  * Get the table name for this repository
7196
8432
  *
@@ -7241,18 +8477,28 @@ var BaseRepository = class {
7241
8477
  /**
7242
8478
  * Find multiple entities with optional filtering, sorting, and pagination
7243
8479
  *
7244
- * @param {QueryOptions<T>} [options] - Optional query configuration with type-safe fields
8480
+ * Accepts either QueryOptions object or a QueryBuilder instance.
8481
+ *
8482
+ * @param {QueryOptions<T> | QueryBuilder<T>} [options] - Query configuration or QueryBuilder
7245
8483
  * @param {OperationConfig} [config] - Optional per-operation configuration (adapter selection, schema override, etc.)
7246
8484
  * @returns {Promise<DatabaseResult<PaginatedResult<T>>>} Promise resolving to paginated results
7247
8485
  *
7248
8486
  * @example
7249
8487
  * ```typescript
8488
+ * // Using QueryOptions (traditional)
7250
8489
  * const result = await userRepository.findMany({
7251
8490
  * filter: { field: 'status', operator: 'eq', value: 'active' },
7252
8491
  * sort: [{ field: 'createdAt', direction: 'desc' }],
7253
8492
  * pagination: { limit: 20, offset: 0 }
7254
8493
  * });
7255
8494
  *
8495
+ * // Using QueryBuilder
8496
+ * const query = QueryBuilder.create<User>()
8497
+ * .where('status', 'eq', 'active')
8498
+ * .orderByDesc('createdAt')
8499
+ * .limit(20);
8500
+ * const result = await userRepository.findMany(query);
8501
+ *
7256
8502
  * // Query from analytics database
7257
8503
  * const analyticsResult = await userRepository.findMany({}, {
7258
8504
  * adapter: 'analytics'
@@ -7260,7 +8506,12 @@ var BaseRepository = class {
7260
8506
  * ```
7261
8507
  */
7262
8508
  async findMany(options, config) {
7263
- return this.db.list(this.tableName, options, this.mergeConfig(config));
8509
+ const queryOptions = options instanceof QueryBuilder ? options.build() : options;
8510
+ return this.db.list(
8511
+ this.tableName,
8512
+ queryOptions,
8513
+ this.mergeConfig(config)
8514
+ );
7264
8515
  }
7265
8516
  /**
7266
8517
  * Create a new entity in the database
@@ -7346,7 +8597,9 @@ var BaseRepository = class {
7346
8597
  /**
7347
8598
  * Count entities matching optional filter criteria
7348
8599
  *
7349
- * @param {Filter<T>} [filter] - Optional filter conditions with type-safe fields
8600
+ * Accepts either a Filter object or a QueryBuilder instance.
8601
+ *
8602
+ * @param {Filter<T> | QueryBuilder<T>} [filter] - Filter conditions or QueryBuilder
7350
8603
  * @param {OperationConfig} [config] - Optional per-operation configuration (adapter selection, schema override, etc.)
7351
8604
  * @returns {Promise<DatabaseResult<number>>} Promise resolving to the count
7352
8605
  *
@@ -7357,6 +8610,12 @@ var BaseRepository = class {
7357
8610
  * field: 'status', operator: 'eq', value: 'active'
7358
8611
  * });
7359
8612
  *
8613
+ * // Using QueryBuilder
8614
+ * const query = QueryBuilder.create<User>()
8615
+ * .where('status', 'eq', 'active')
8616
+ * .andWhere('verified', 'eq', true);
8617
+ * const result = await userRepository.count(query);
8618
+ *
7360
8619
  * // Count in specific adapter
7361
8620
  * const archiveCount = await userRepository.count(undefined, {
7362
8621
  * adapter: 'archive'
@@ -7364,7 +8623,12 @@ var BaseRepository = class {
7364
8623
  * ```
7365
8624
  */
7366
8625
  async count(filter, config) {
7367
- return this.db.count(this.tableName, filter, this.mergeConfig(config));
8626
+ const filterOptions = filter instanceof QueryBuilder ? filter.toFilters()[0] : filter;
8627
+ return this.db.count(
8628
+ this.tableName,
8629
+ filterOptions,
8630
+ this.mergeConfig(config)
8631
+ );
7368
8632
  }
7369
8633
  /**
7370
8634
  * Check if an entity exists by ID
@@ -7401,7 +8665,9 @@ var BaseRepository = class {
7401
8665
  /**
7402
8666
  * Find the first entity matching filter criteria
7403
8667
  *
7404
- * @param {Filter<T>} filter - Filter conditions with type-safe fields
8668
+ * Accepts either a Filter object or a QueryBuilder instance.
8669
+ *
8670
+ * @param {Filter<T> | QueryBuilder<T>} filter - Filter conditions or QueryBuilder
7405
8671
  * @param {OperationConfig} [config] - Optional per-operation configuration (adapter selection, schema override, etc.)
7406
8672
  * @returns {Promise<DatabaseResult<T | null>>} Promise resolving to first match or null
7407
8673
  *
@@ -7411,6 +8677,12 @@ var BaseRepository = class {
7411
8677
  * field: 'email', operator: 'eq', value: 'john@example.com'
7412
8678
  * });
7413
8679
  *
8680
+ * // Using QueryBuilder
8681
+ * const query = QueryBuilder.create<User>()
8682
+ * .where('email', 'eq', 'john@example.com')
8683
+ * .andWhere('status', 'eq', 'active');
8684
+ * const result = await userRepository.findOne(query);
8685
+ *
7414
8686
  * // Find in specific adapter
7415
8687
  * const archivedUser = await userRepository.findOne({
7416
8688
  * field: 'email', operator: 'eq', value: 'john@example.com'
@@ -7421,7 +8693,19 @@ var BaseRepository = class {
7421
8693
  * ```
7422
8694
  */
7423
8695
  async findOne(filter, config) {
7424
- return this.db.findOne(this.tableName, filter, this.mergeConfig(config));
8696
+ const filterOptions = filter instanceof QueryBuilder ? filter.toFilters()[0] : filter;
8697
+ if (!filterOptions) {
8698
+ return {
8699
+ success: false,
8700
+ value: null,
8701
+ error: new Error("findOne requires at least one filter condition")
8702
+ };
8703
+ }
8704
+ return this.db.findOne(
8705
+ this.tableName,
8706
+ filterOptions,
8707
+ this.mergeConfig(config)
8708
+ );
7425
8709
  }
7426
8710
  /**
7427
8711
  * Soft delete an entity by ID (recoverable deletion)
@@ -11371,6 +12655,6 @@ var SeedManager = class {
11371
12655
  }
11372
12656
  };
11373
12657
 
11374
- export { AdapterFactory, AlertManager, AuditAdapter, BackupService, BaseRepository, CacheEvict, Cacheable, CachingAdapter, ConfigMerger, DataValidationPipe, DatabaseEventEmitter, DatabaseService, DrizzleAdapter, DynamicPool, EncryptionAdapter, HealthManager, MetricsCollector, MigrationManager, MockAdapter, MultiReadAdapter, MultiWriteAdapter, ReadReplicaAdapter, RedisCache, SQLAdapter, SanitizeHtmlPipe, SeedManager, ShardKeyManager, ShardRouter, SoftDeleteAdapter, SupabaseAdapter, TenantContext, TenantRepository, UseReplica, buildOrderClause, buildOrderClauseORM, buildPaginationClause, buildPaginationClauseORM, buildWhereClause, buildWhereClauseORM, createDatabaseService };
12658
+ export { AdapterFactory, AlertManager, AuditAdapter, BackupService, BaseRepository, CacheEvict, Cacheable, CachingAdapter, ConfigMerger, DataValidationPipe, DatabaseEventEmitter, DatabaseService, DrizzleAdapter, DynamicPool, EncryptionAdapter, HealthManager, MetricsCollector, MigrationManager, MockAdapter, MultiReadAdapter, MultiWriteAdapter, QueryBuilder, ReadReplicaAdapter, RedisCache, SQLAdapter, SanitizeHtmlPipe, SeedManager, ShardKeyManager, ShardRouter, SoftDeleteAdapter, SupabaseAdapter, TenantContext, TenantRepository, UseReplica, buildOrderClause, buildOrderClauseORM, buildPaginationClause, buildPaginationClauseORM, buildWhereClause, buildWhereClauseORM, createDatabaseService };
11375
12659
  //# sourceMappingURL=index.mjs.map
11376
12660
  //# sourceMappingURL=index.mjs.map