@onchaindb/sdk 0.4.5 → 2.0.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.
Files changed (117) hide show
  1. package/.claude/settings.local.json +10 -2
  2. package/README.md +422 -355
  3. package/dist/batch.d.ts +1 -10
  4. package/dist/batch.d.ts.map +1 -1
  5. package/dist/batch.js +4 -26
  6. package/dist/batch.js.map +1 -1
  7. package/dist/client.d.ts +31 -46
  8. package/dist/client.d.ts.map +1 -1
  9. package/dist/client.js +222 -357
  10. package/dist/client.js.map +1 -1
  11. package/dist/database.d.ts +14 -131
  12. package/dist/database.d.ts.map +1 -1
  13. package/dist/database.js +35 -131
  14. package/dist/database.js.map +1 -1
  15. package/dist/index.d.ts +10 -13
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +4 -18
  18. package/dist/index.js.map +1 -1
  19. package/dist/query-sdk/ConditionBuilder.d.ts +3 -11
  20. package/dist/query-sdk/ConditionBuilder.d.ts.map +1 -1
  21. package/dist/query-sdk/ConditionBuilder.js +10 -48
  22. package/dist/query-sdk/ConditionBuilder.js.map +1 -1
  23. package/dist/query-sdk/NestedBuilders.d.ts +33 -30
  24. package/dist/query-sdk/NestedBuilders.d.ts.map +1 -1
  25. package/dist/query-sdk/NestedBuilders.js +46 -43
  26. package/dist/query-sdk/NestedBuilders.js.map +1 -1
  27. package/{src/query-sdk/dist/OnChainDB.d.ts → dist/query-sdk/OnDB.d.ts} +10 -2
  28. package/dist/query-sdk/OnDB.d.ts.map +1 -0
  29. package/{src/query-sdk/dist/OnChainDB.js → dist/query-sdk/OnDB.js} +86 -18
  30. package/dist/query-sdk/OnDB.js.map +1 -0
  31. package/dist/query-sdk/QueryBuilder.d.ts +4 -2
  32. package/dist/query-sdk/QueryBuilder.d.ts.map +1 -1
  33. package/dist/query-sdk/QueryBuilder.js +47 -169
  34. package/dist/query-sdk/QueryBuilder.js.map +1 -1
  35. package/dist/query-sdk/QueryResult.d.ts +0 -38
  36. package/dist/query-sdk/QueryResult.d.ts.map +1 -1
  37. package/dist/query-sdk/QueryResult.js +1 -227
  38. package/dist/query-sdk/QueryResult.js.map +1 -1
  39. package/dist/query-sdk/index.d.ts +2 -2
  40. package/dist/query-sdk/index.d.ts.map +1 -1
  41. package/dist/query-sdk/index.js +3 -3
  42. package/dist/query-sdk/index.js.map +1 -1
  43. package/dist/query-sdk/operators.d.ts +32 -28
  44. package/dist/query-sdk/operators.d.ts.map +1 -1
  45. package/dist/query-sdk/operators.js +45 -155
  46. package/dist/query-sdk/operators.js.map +1 -1
  47. package/dist/types.d.ts +159 -36
  48. package/dist/types.d.ts.map +1 -1
  49. package/dist/types.js +8 -8
  50. package/dist/types.js.map +1 -1
  51. package/dist/x402/types.d.ts +1 -1
  52. package/dist/x402/types.d.ts.map +1 -1
  53. package/dist/x402/utils.js +2 -2
  54. package/dist/x402/utils.js.map +1 -1
  55. package/jest.config.js +4 -0
  56. package/package.json +1 -1
  57. package/skills.md +0 -1
  58. package/src/batch.d.ts +3 -3
  59. package/src/batch.js +1 -1
  60. package/src/client.ts +287 -823
  61. package/src/database.d.ts +1 -1
  62. package/src/database.js +4 -4
  63. package/src/database.ts +71 -494
  64. package/src/index.d.ts +18 -18
  65. package/src/index.js +16 -16
  66. package/src/index.ts +44 -198
  67. package/src/query-sdk/ConditionBuilder.ts +37 -89
  68. package/src/query-sdk/NestedBuilders.ts +90 -92
  69. package/src/query-sdk/{OnChainDB.ts → OnDB.ts} +1 -1
  70. package/src/query-sdk/QueryBuilder.ts +59 -218
  71. package/src/query-sdk/QueryResult.ts +4 -330
  72. package/src/query-sdk/README.md +218 -587
  73. package/src/query-sdk/index.ts +2 -2
  74. package/src/query-sdk/operators.ts +91 -200
  75. package/src/query-sdk/tests/FieldConditionBuilder.test.ts +70 -71
  76. package/src/query-sdk/tests/LogicalOperator.test.ts +43 -82
  77. package/src/query-sdk/tests/NestedBuilders.test.ts +229 -309
  78. package/src/query-sdk/tests/QueryBuilder.test.ts +5 -5
  79. package/src/query-sdk/tests/QueryResult.test.ts +41 -435
  80. package/src/query-sdk/tests/comprehensive.test.ts +4 -185
  81. package/src/tests/client-requests.test.ts +280 -0
  82. package/src/tests/client-validation.test.ts +80 -0
  83. package/src/types.d.ts +6 -6
  84. package/src/types.js +8 -8
  85. package/src/types.ts +239 -54
  86. package/src/x402/types.ts +3 -3
  87. package/src/x402/utils.ts +3 -3
  88. package/examples/blob-upload-example.ts +0 -140
  89. package/src/batch.ts +0 -257
  90. package/src/query-sdk/dist/ConditionBuilder.d.ts +0 -22
  91. package/src/query-sdk/dist/ConditionBuilder.js +0 -90
  92. package/src/query-sdk/dist/FieldConditionBuilder.d.ts +0 -1
  93. package/src/query-sdk/dist/FieldConditionBuilder.js +0 -6
  94. package/src/query-sdk/dist/NestedBuilders.d.ts +0 -43
  95. package/src/query-sdk/dist/NestedBuilders.js +0 -144
  96. package/src/query-sdk/dist/QueryBuilder.d.ts +0 -70
  97. package/src/query-sdk/dist/QueryBuilder.js +0 -295
  98. package/src/query-sdk/dist/QueryResult.d.ts +0 -52
  99. package/src/query-sdk/dist/QueryResult.js +0 -293
  100. package/src/query-sdk/dist/SelectionBuilder.d.ts +0 -20
  101. package/src/query-sdk/dist/SelectionBuilder.js +0 -80
  102. package/src/query-sdk/dist/adapters/HttpClientAdapter.d.ts +0 -27
  103. package/src/query-sdk/dist/adapters/HttpClientAdapter.js +0 -170
  104. package/src/query-sdk/dist/index.d.ts +0 -36
  105. package/src/query-sdk/dist/index.js +0 -27
  106. package/src/query-sdk/dist/operators.d.ts +0 -56
  107. package/src/query-sdk/dist/operators.js +0 -289
  108. package/src/query-sdk/dist/tests/setup.d.ts +0 -15
  109. package/src/query-sdk/dist/tests/setup.js +0 -46
  110. package/src/query-sdk/jest.config.js +0 -25
  111. package/src/query-sdk/package.json +0 -46
  112. package/src/query-sdk/tests/aggregations.test.ts +0 -653
  113. package/src/query-sdk/tests/integration.test.ts +0 -608
  114. package/src/query-sdk/tests/operators.test.ts +0 -327
  115. package/src/query-sdk/tests/unit.test.ts +0 -794
  116. package/src/query-sdk/tsconfig.json +0 -26
  117. package/src/query-sdk/yarn.lock +0 -3092
@@ -1,4 +1,4 @@
1
- import { LogicalOperator, FieldConditionBuilder, Condition } from './operators';
1
+ import { LogicalOperator } from './operators';
2
2
 
3
3
  // Builder for creating nested field conditions with ORM-like syntax
4
4
  export class NestedConditionBuilder {
@@ -8,179 +8,177 @@ export class NestedConditionBuilder {
8
8
  this.path = [rootField];
9
9
  }
10
10
 
11
- // Add another level to the path and create field conditions
12
11
  field(fieldName: string): NestedFieldConditionBuilder {
13
- const newPath = [...this.path, fieldName];
14
- return new NestedFieldConditionBuilder(newPath);
12
+ return new NestedFieldConditionBuilder([...this.path, fieldName]);
15
13
  }
16
14
 
17
- // Create nested structure with callback
18
15
  nested(fieldName: string, builderFn: (builder: NestedConditionBuilder) => LogicalOperator): LogicalOperator {
19
- const nestedPath = [...this.path, fieldName];
20
16
  const nestedBuilder = new NestedConditionBuilder('');
21
- nestedBuilder.path = nestedPath;
17
+ nestedBuilder.path = [...this.path, fieldName];
22
18
  return builderFn(nestedBuilder);
23
19
  }
24
20
 
25
- // Create logical groups
26
- andGroup(builderFn: (builder: NestedConditionBuilder) => LogicalOperator[]): LogicalOperator {
27
- const conditions = builderFn(this);
21
+ // Logical group helpers — pass conditions as variadic args or chain on the result
22
+ and(...conditions: LogicalOperator[]): LogicalOperator {
28
23
  return LogicalOperator.And(conditions);
29
24
  }
30
25
 
31
- orGroup(builderFn: (builder: NestedConditionBuilder) => LogicalOperator[]): LogicalOperator {
32
- const conditions = builderFn(this);
26
+ or(...conditions: LogicalOperator[]): LogicalOperator {
33
27
  return LogicalOperator.Or(conditions);
34
28
  }
35
29
 
36
- notGroup(builderFn: (builder: NestedConditionBuilder) => LogicalOperator[]): LogicalOperator {
37
- const conditions = builderFn(this);
30
+ not(...conditions: LogicalOperator[]): LogicalOperator {
38
31
  return LogicalOperator.Not(conditions);
39
32
  }
40
- }
41
33
 
42
- // Builder for field conditions within nested structures
43
- // Only includes operators that actually exist in the Rust implementation
44
- export class NestedFieldConditionBuilder {
45
- private fieldPath: string[];
34
+ // Callback-style group helpers (kept for compatibility)
35
+ andGroup(builderFn: (builder: NestedConditionBuilder) => LogicalOperator[]): LogicalOperator {
36
+ return LogicalOperator.And(builderFn(this));
37
+ }
38
+
39
+ orGroup(builderFn: (builder: NestedConditionBuilder) => LogicalOperator[]): LogicalOperator {
40
+ return LogicalOperator.Or(builderFn(this));
41
+ }
46
42
 
47
- constructor(fieldPath: string[]) {
48
- this.fieldPath = fieldPath;
43
+ notGroup(builderFn: (builder: NestedConditionBuilder) => LogicalOperator[]): LogicalOperator {
44
+ return LogicalOperator.Not(builderFn(this));
49
45
  }
46
+ }
50
47
 
51
- private createCondition(operator: string, value: any): Condition {
52
- const path = this.fieldPath.join('.');
53
- return {
54
- field: path,
48
+ // Builder for field conditions within nested structures.
49
+ // All methods return LogicalOperator directly — no wrapping needed at call sites.
50
+ export class NestedFieldConditionBuilder {
51
+ constructor(private fieldPath: string[]) {}
52
+
53
+ private cond(operator: string, value: any): LogicalOperator {
54
+ return LogicalOperator.Condition({
55
+ field: this.fieldPath.join('.'),
55
56
  operator,
56
57
  value
57
- };
58
+ });
58
59
  }
59
60
 
60
- // ===== BASE OPERATORS (BaseOperator) =====
61
+ // ===== BASE OPERATORS =====
61
62
 
62
- equals(value: any): Condition {
63
- return this.createCondition('is', value);
63
+ equals(value: any): LogicalOperator {
64
+ return this.cond('is', value);
64
65
  }
65
66
 
66
- notEquals(value: any): Condition {
67
- return this.createCondition('isNot', value);
67
+ notEquals(value: any): LogicalOperator {
68
+ return this.cond('isNot', value);
68
69
  }
69
70
 
70
- in(values: any[]): Condition {
71
- return this.createCondition('in', values);
71
+ in(values: any[]): LogicalOperator {
72
+ return this.cond('in', values);
72
73
  }
73
74
 
74
- notIn(values: any[]): Condition {
75
- return this.createCondition('notIn', values);
75
+ notIn(values: any[]): LogicalOperator {
76
+ return this.cond('notIn', values);
76
77
  }
77
78
 
78
- isNull(): Condition {
79
- return this.createCondition('isNull', true);
79
+ isNull(): LogicalOperator {
80
+ return this.cond('isNull', true);
80
81
  }
81
82
 
82
- isNotNull(): Condition {
83
- return this.createCondition('isNull', false);
83
+ isNotNull(): LogicalOperator {
84
+ return this.cond('isNull', false);
84
85
  }
85
86
 
86
- exists(): Condition {
87
- return this.createCondition('exists', true);
87
+ exists(): LogicalOperator {
88
+ return this.cond('exists', true);
88
89
  }
89
90
 
90
- notExists(): Condition {
91
- return this.createCondition('exists', false);
91
+ notExists(): LogicalOperator {
92
+ return this.cond('exists', false);
92
93
  }
93
94
 
94
- // ===== STRING OPERATORS (StringOperator) =====
95
+ // ===== STRING OPERATORS =====
95
96
 
96
- startsWith(value: string): Condition {
97
- return this.createCondition('startsWith', value);
97
+ startsWith(value: string): LogicalOperator {
98
+ return this.cond('startsWith', value);
98
99
  }
99
100
 
100
- endsWith(value: string): Condition {
101
- return this.createCondition('endsWith', value);
101
+ endsWith(value: string): LogicalOperator {
102
+ return this.cond('endsWith', value);
102
103
  }
103
104
 
104
- contains(value: string): Condition {
105
- return this.createCondition('includes', value);
105
+ contains(value: string): LogicalOperator {
106
+ return this.cond('includes', value);
106
107
  }
107
108
 
108
- regExpMatches(pattern: string): Condition {
109
- return this.createCondition('regExpMatches', pattern);
109
+ regExpMatches(pattern: string): LogicalOperator {
110
+ return this.cond('regExpMatches', pattern);
110
111
  }
111
112
 
112
- includesCaseInsensitive(value: string): Condition {
113
- return this.createCondition('includesCaseInsensitive', value);
113
+ includesCaseInsensitive(value: string): LogicalOperator {
114
+ return this.cond('includesCaseInsensitive', value);
114
115
  }
115
116
 
116
- startsWithCaseInsensitive(value: string): Condition {
117
- return this.createCondition('startsWithCaseInsensitive', value);
117
+ startsWithCaseInsensitive(value: string): LogicalOperator {
118
+ return this.cond('startsWithCaseInsensitive', value);
118
119
  }
119
120
 
120
- endsWithCaseInsensitive(value: string): Condition {
121
- return this.createCondition('endsWithCaseInsensitive', value);
121
+ endsWithCaseInsensitive(value: string): LogicalOperator {
122
+ return this.cond('endsWithCaseInsensitive', value);
122
123
  }
123
124
 
124
- // ===== NUMBER OPERATORS (NumberOperator) =====
125
-
126
- greaterThan(value: any): Condition {
127
- return this.createCondition('greaterThan', value);
128
- }
125
+ // ===== NUMBER OPERATORS =====
129
126
 
130
- lessThan(value: any): Condition {
131
- return this.createCondition('lessThan', value);
127
+ greaterThan(value: any): LogicalOperator {
128
+ return this.cond('greaterThan', value);
132
129
  }
133
130
 
134
- greaterThanOrEqual(value: any): Condition {
135
- return this.createCondition('greaterThanOrEqual', value);
131
+ lessThan(value: any): LogicalOperator {
132
+ return this.cond('lessThan', value);
136
133
  }
137
134
 
138
- lessThanOrEqual(value: any): Condition {
139
- return this.createCondition('lessThanOrEqual', value);
135
+ greaterThanOrEqual(value: any): LogicalOperator {
136
+ return this.cond('greaterThanOrEqual', value);
140
137
  }
141
138
 
142
- // ===== IP OPERATORS (IpOperator) =====
143
-
144
- isLocalIp(): Condition {
145
- return this.createCondition('isLocalIp', true);
139
+ lessThanOrEqual(value: any): LogicalOperator {
140
+ return this.cond('lessThanOrEqual', value);
146
141
  }
147
142
 
148
- isExternalIp(): Condition {
149
- return this.createCondition('isExternalIp', true);
143
+ between(min: any, max: any): LogicalOperator {
144
+ return this.cond('betweenOp', { from: min, to: max });
150
145
  }
151
146
 
152
- // ===== MISC OPERATORS (MiscOperator) =====
147
+ // ===== IP OPERATORS =====
153
148
 
154
- b64(value: string): Condition {
155
- return this.createCondition('b64', value);
149
+ isLocalIp(): LogicalOperator {
150
+ return this.cond('isLocalIp', true);
156
151
  }
157
152
 
158
- inDataset(dataset: string): Condition {
159
- return this.createCondition('inDataset', dataset);
153
+ isExternalIp(): LogicalOperator {
154
+ return this.cond('isExternalIp', true);
160
155
  }
161
156
 
162
- inCountry(countryCode: string): Condition {
163
- return this.createCondition('inCountry', countryCode);
157
+ // ===== MISC OPERATORS =====
158
+
159
+ b64(value: string): LogicalOperator {
160
+ return this.cond('b64', value);
164
161
  }
165
162
 
166
- cidr(cidr: string): Condition {
167
- return this.createCondition('CIDR', cidr);
163
+ inDataset(dataset: string): LogicalOperator {
164
+ return this.cond('inDataset', dataset);
168
165
  }
169
166
 
170
- // ===== BETWEEN OPERATOR =====
167
+ inCountry(countryCode: string): LogicalOperator {
168
+ return this.cond('inCountry', countryCode);
169
+ }
171
170
 
172
- between(min: any, max: any): Condition {
173
- return this.createCondition('between', { from: min, to: max });
171
+ cidr(cidr: string): LogicalOperator {
172
+ return this.cond('CIDR', cidr);
174
173
  }
175
174
 
176
- // ===== CONVENIENCE METHODS =====
175
+ // ===== CONVENIENCE =====
177
176
 
178
- // Boolean checks (using base operators)
179
- isTrue(): Condition {
177
+ isTrue(): LogicalOperator {
180
178
  return this.equals(true);
181
179
  }
182
180
 
183
- isFalse(): Condition {
181
+ isFalse(): LogicalOperator {
184
182
  return this.equals(false);
185
183
  }
186
- }
184
+ }
@@ -3,7 +3,7 @@ import {SelectionBuilder} from './SelectionBuilder';
3
3
  import {FieldMap, HttpClient, QueryRequest, QueryResponse, QueryValue} from "./index";
4
4
 
5
5
  // Main SDK class providing static methods for query building
6
- export class OnChainDB {
6
+ export class OnDB {
7
7
  private static httpClient?: HttpClient;
8
8
  private static serverUrl?: string;
9
9
  private static apiKey?: string;
@@ -1,11 +1,11 @@
1
- import {QueryRequest, QueryResponse, QueryValue, SelectionMap, Val, PaymentRequiredError} from '../index';
1
+ import {QueryRequest, QueryResponse, SelectionMap, Val, PaymentRequiredError} from '../index';
2
+ import {QueryValue} from './index';
2
3
  import {FieldConditionBuilder, LogicalOperator} from './operators';
3
4
  import {SelectionBuilder} from './SelectionBuilder';
4
5
  import {ConditionBuilder} from './ConditionBuilder';
5
6
  import {FieldMap, HttpClient} from "./index";
6
7
  import {AxiosError} from "axios";
7
8
  import {
8
- X402PaymentRequirement,
9
9
  X402PaymentRequiredResponse,
10
10
  encodePaymentHeader,
11
11
  requirementToQuote,
@@ -68,10 +68,12 @@ export class QueryBuilder {
68
68
  return this;
69
69
  }
70
70
 
71
- // Build find conditions using a builder function
72
- find(builderFn: (builder: ConditionBuilder) => LogicalOperator): QueryBuilder {
71
+ // Build find conditions using a builder function.
72
+ // Return a single LogicalOperator, or an array — arrays are automatically wrapped in AND.
73
+ find(builderFn: (builder: ConditionBuilder) => LogicalOperator | LogicalOperator[]): QueryBuilder {
73
74
  const conditionBuilder = new ConditionBuilder();
74
- this.findConditions = builderFn(conditionBuilder);
75
+ const result = builderFn(conditionBuilder);
76
+ this.findConditions = Array.isArray(result) ? LogicalOperator.And(result) : result;
75
77
  return this;
76
78
  }
77
79
 
@@ -509,6 +511,7 @@ export class QueryBuilder {
509
511
  limit: this.limitValue,
510
512
  offset: this.offsetValue,
511
513
  sortBy: this.sortBy,
514
+ sortDirection: this.sortDirection,
512
515
  root: `${this.app}::${this.collectionName}`
513
516
  };
514
517
  }
@@ -525,7 +528,8 @@ export class QueryBuilder {
525
528
  ...this.buildQueryValue(),
526
529
  limit: this.limitValue,
527
530
  offset: this.offsetValue,
528
- sortBy: this.sortBy
531
+ sortBy: this.sortBy,
532
+ sortDirection: this.sortDirection,
529
533
  };
530
534
  }
531
535
 
@@ -538,6 +542,7 @@ export class QueryBuilder {
538
542
  cloned.limitValue = this.limitValue;
539
543
  cloned.offsetValue = this.offsetValue;
540
544
  cloned.sortBy = this.sortBy;
545
+ cloned.sortDirection = this.sortDirection;
541
546
  cloned.includeHistoryValue = this.includeHistoryValue;
542
547
  cloned.collectionName = this.collectionName;
543
548
  cloned.serverJoinConfigs = [...this.serverJoinConfigs]; // Deep copy server join configs
@@ -703,189 +708,47 @@ export class QueryBuilder {
703
708
  }
704
709
  }
705
710
 
706
- // Helper class for building where clauses with method chaining
711
+ // Helper class for building where clauses with method chaining.
712
+ // FieldConditionBuilder methods already return LogicalOperator — assign directly.
707
713
  export class WhereClause {
708
714
  constructor(
709
715
  private queryBuilder: QueryBuilder,
710
716
  private fieldName: string
711
- ) {
712
- }
713
-
714
- equals(value: Val): QueryBuilder {
715
- const condition = new FieldConditionBuilder(this.fieldName).equals(value);
716
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
717
- return this.queryBuilder;
718
- }
719
-
720
- notEquals(value: Val): QueryBuilder {
721
- const condition = new FieldConditionBuilder(this.fieldName).notEquals(value);
722
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
723
- return this.queryBuilder;
724
- }
725
-
726
- greaterThan(value: Val): QueryBuilder {
727
- const condition = new FieldConditionBuilder(this.fieldName).greaterThan(value);
728
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
729
- return this.queryBuilder;
730
- }
731
-
732
- greaterThanOrEqual(value: Val): QueryBuilder {
733
- const condition = new FieldConditionBuilder(this.fieldName).greaterThanOrEqual(value);
734
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
735
- return this.queryBuilder;
736
- }
737
-
738
- lessThan(value: Val): QueryBuilder {
739
- const condition = new FieldConditionBuilder(this.fieldName).lessThan(value);
740
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
741
- return this.queryBuilder;
742
- }
743
-
744
- lessThanOrEqual(value: Val): QueryBuilder {
745
- const condition = new FieldConditionBuilder(this.fieldName).lessThanOrEqual(value);
746
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
747
- return this.queryBuilder;
748
- }
749
-
750
- contains(value: string): QueryBuilder {
751
- const condition = new FieldConditionBuilder(this.fieldName).contains(value);
752
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
753
- return this.queryBuilder;
754
- }
755
-
756
- startsWith(value: string): QueryBuilder {
757
- const condition = new FieldConditionBuilder(this.fieldName).startsWith(value);
758
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
759
- return this.queryBuilder;
760
- }
761
-
762
- endsWith(value: string): QueryBuilder {
763
- const condition = new FieldConditionBuilder(this.fieldName).endsWith(value);
764
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
765
- return this.queryBuilder;
766
- }
767
-
768
- in(values: Val[]): QueryBuilder {
769
- const condition = new FieldConditionBuilder(this.fieldName).in(values);
770
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
771
- return this.queryBuilder;
772
- }
773
-
774
- notIn(values: Val[]): QueryBuilder {
775
- const condition = new FieldConditionBuilder(this.fieldName).notIn(values);
776
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
777
- return this.queryBuilder;
778
- }
779
-
780
- exists(): QueryBuilder {
781
- const condition = new FieldConditionBuilder(this.fieldName).exists();
782
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
783
- return this.queryBuilder;
784
- }
785
-
786
- notExists(): QueryBuilder {
787
- const condition = new FieldConditionBuilder(this.fieldName).notExists();
788
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
789
- return this.queryBuilder;
790
- }
791
-
792
- isNull(): QueryBuilder {
793
- const condition = new FieldConditionBuilder(this.fieldName).isNull();
794
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
795
- return this.queryBuilder;
796
- }
797
-
798
- isNotNull(): QueryBuilder {
799
- const condition = new FieldConditionBuilder(this.fieldName).isNotNull();
800
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
801
- return this.queryBuilder;
802
- }
803
-
804
- regExpMatches(pattern: string): QueryBuilder {
805
- const condition = new FieldConditionBuilder(this.fieldName).regExpMatches(pattern);
806
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
807
- return this.queryBuilder;
808
- }
809
-
810
- includesCaseInsensitive(value: string): QueryBuilder {
811
- const condition = new FieldConditionBuilder(this.fieldName).includesCaseInsensitive(value);
812
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
813
- return this.queryBuilder;
814
- }
815
-
816
- startsWithCaseInsensitive(value: string): QueryBuilder {
817
- const condition = new FieldConditionBuilder(this.fieldName).startsWithCaseInsensitive(value);
818
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
819
- return this.queryBuilder;
820
- }
821
-
822
- endsWithCaseInsensitive(value: string): QueryBuilder {
823
- const condition = new FieldConditionBuilder(this.fieldName).endsWithCaseInsensitive(value);
824
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
825
- return this.queryBuilder;
826
- }
827
-
828
- // ===== IP OPERATORS =====
829
-
830
- isLocalIp(): QueryBuilder {
831
- const condition = new FieldConditionBuilder(this.fieldName).isLocalIp();
832
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
833
- return this.queryBuilder;
834
- }
835
-
836
- isExternalIp(): QueryBuilder {
837
- const condition = new FieldConditionBuilder(this.fieldName).isExternalIp();
838
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
839
- return this.queryBuilder;
840
- }
841
-
842
- // ===== MISC OPERATORS =====
843
-
844
- b64(value: string): QueryBuilder {
845
- const condition = new FieldConditionBuilder(this.fieldName).b64(value);
846
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
847
- return this.queryBuilder;
848
- }
849
-
850
- inDataset(dataset: string): QueryBuilder {
851
- const condition = new FieldConditionBuilder(this.fieldName).inDataset(dataset);
852
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
853
- return this.queryBuilder;
854
- }
855
-
856
- inCountry(countryCode: string): QueryBuilder {
857
- const condition = new FieldConditionBuilder(this.fieldName).inCountry(countryCode);
858
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
859
- return this.queryBuilder;
860
- }
861
-
862
- cidr(cidr: string): QueryBuilder {
863
- const condition = new FieldConditionBuilder(this.fieldName).cidr(cidr);
864
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
865
- return this.queryBuilder;
866
- }
867
-
868
- // ===== BETWEEN OPERATOR =====
869
-
870
- between(min: any, max: any): QueryBuilder {
871
- const condition = new FieldConditionBuilder(this.fieldName).between(min, max);
872
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
873
- return this.queryBuilder;
874
- }
875
-
876
- // ===== CONVENIENCE METHODS =====
717
+ ) {}
877
718
 
878
- isTrue(): QueryBuilder {
879
- const condition = new FieldConditionBuilder(this.fieldName).isTrue();
880
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
719
+ private set(op: LogicalOperator): QueryBuilder {
720
+ (this.queryBuilder as any).findConditions = op;
881
721
  return this.queryBuilder;
882
722
  }
883
723
 
884
- isFalse(): QueryBuilder {
885
- const condition = new FieldConditionBuilder(this.fieldName).isFalse();
886
- (this.queryBuilder as any).findConditions = LogicalOperator.Condition(condition);
887
- return this.queryBuilder;
888
- }
724
+ equals(value: Val): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).equals(value)); }
725
+ notEquals(value: Val): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).notEquals(value)); }
726
+ greaterThan(value: Val): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).greaterThan(value)); }
727
+ greaterThanOrEqual(value: Val): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).greaterThanOrEqual(value)); }
728
+ lessThan(value: Val): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).lessThan(value)); }
729
+ lessThanOrEqual(value: Val): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).lessThanOrEqual(value)); }
730
+ contains(value: string): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).contains(value)); }
731
+ startsWith(value: string): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).startsWith(value)); }
732
+ endsWith(value: string): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).endsWith(value)); }
733
+ in(values: Val[]): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).in(values)); }
734
+ notIn(values: Val[]): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).notIn(values)); }
735
+ exists(): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).exists()); }
736
+ notExists(): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).notExists()); }
737
+ isNull(): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).isNull()); }
738
+ isNotNull(): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).isNotNull()); }
739
+ regExpMatches(pattern: string): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).regExpMatches(pattern)); }
740
+ includesCaseInsensitive(value: string): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).includesCaseInsensitive(value)); }
741
+ startsWithCaseInsensitive(value: string): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).startsWithCaseInsensitive(value)); }
742
+ endsWithCaseInsensitive(value: string): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).endsWithCaseInsensitive(value)); }
743
+ isLocalIp(): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).isLocalIp()); }
744
+ isExternalIp(): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).isExternalIp()); }
745
+ b64(value: string): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).b64(value)); }
746
+ inDataset(dataset: string): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).inDataset(dataset)); }
747
+ inCountry(countryCode: string): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).inCountry(countryCode)); }
748
+ cidr(cidr: string): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).cidr(cidr)); }
749
+ between(min: any, max: any): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).between(min, max)); }
750
+ isTrue(): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).isTrue()); }
751
+ isFalse(): QueryBuilder { return this.set(new FieldConditionBuilder(this.fieldName).isFalse()); }
889
752
  }
890
753
 
891
754
  // Fluent builder for constructing server-side JOINs
@@ -905,10 +768,13 @@ export class JoinBuilder<TParent extends QueryBuilder | JoinBuilder<any> = Query
905
768
  this.many = many;
906
769
  }
907
770
 
908
- // Add filter conditions for the joined collection
909
- on(builderFn: (builder: ConditionBuilder) => LogicalOperator): this {
771
+ // Add filter conditions for the joined collection.
772
+ // Return a single LogicalOperator, or an array — arrays are automatically wrapped in AND.
773
+ on(builderFn: (builder: ConditionBuilder) => LogicalOperator | LogicalOperator[]): this {
910
774
  const conditionBuilder = new ConditionBuilder();
911
- this.findConditions = builderFn(conditionBuilder).toComposable();
775
+ const result = builderFn(conditionBuilder);
776
+ const op = Array.isArray(result) ? LogicalOperator.And(result) : result;
777
+ this.findConditions = op.toComposable();
912
778
  return this;
913
779
  }
914
780
 
@@ -1006,44 +872,19 @@ export class JoinWhereClause<TParent extends QueryBuilder | JoinBuilder<any> = Q
1006
872
  constructor(
1007
873
  private joinBuilder: JoinBuilder<TParent>,
1008
874
  private fieldName: string
1009
- ) {
1010
- }
1011
-
1012
- equals(value: Val): JoinBuilder<TParent> {
1013
- const condition = new FieldConditionBuilder(this.fieldName).equals(value);
1014
- this.joinBuilder._setFindConditions(LogicalOperator.Condition(condition).toComposable());
1015
- return this.joinBuilder;
1016
- }
1017
-
1018
- in(values: Val[]): JoinBuilder<TParent> {
1019
- const condition = new FieldConditionBuilder(this.fieldName).in(values);
1020
- this.joinBuilder._setFindConditions(LogicalOperator.Condition(condition).toComposable());
1021
- return this.joinBuilder;
1022
- }
1023
-
1024
- greaterThan(value: Val): JoinBuilder<TParent> {
1025
- const condition = new FieldConditionBuilder(this.fieldName).greaterThan(value);
1026
- this.joinBuilder._setFindConditions(LogicalOperator.Condition(condition).toComposable());
1027
- return this.joinBuilder;
1028
- }
1029
-
1030
- lessThan(value: Val): JoinBuilder<TParent> {
1031
- const condition = new FieldConditionBuilder(this.fieldName).lessThan(value);
1032
- this.joinBuilder._setFindConditions(LogicalOperator.Condition(condition).toComposable());
1033
- return this.joinBuilder;
1034
- }
875
+ ) {}
1035
876
 
1036
- isNull(): JoinBuilder<TParent> {
1037
- const condition = new FieldConditionBuilder(this.fieldName).isNull();
1038
- this.joinBuilder._setFindConditions(LogicalOperator.Condition(condition).toComposable());
877
+ private set(op: LogicalOperator): JoinBuilder<TParent> {
878
+ this.joinBuilder._setFindConditions(op.toComposable());
1039
879
  return this.joinBuilder;
1040
880
  }
1041
881
 
1042
- isNotNull(): JoinBuilder<TParent> {
1043
- const condition = new FieldConditionBuilder(this.fieldName).isNotNull();
1044
- this.joinBuilder._setFindConditions(LogicalOperator.Condition(condition).toComposable());
1045
- return this.joinBuilder;
1046
- }
882
+ equals(value: Val): JoinBuilder<TParent> { return this.set(new FieldConditionBuilder(this.fieldName).equals(value)); }
883
+ in(values: Val[]): JoinBuilder<TParent> { return this.set(new FieldConditionBuilder(this.fieldName).in(values)); }
884
+ greaterThan(value: Val): JoinBuilder<TParent> { return this.set(new FieldConditionBuilder(this.fieldName).greaterThan(value)); }
885
+ lessThan(value: Val): JoinBuilder<TParent> { return this.set(new FieldConditionBuilder(this.fieldName).lessThan(value)); }
886
+ isNull(): JoinBuilder<TParent> { return this.set(new FieldConditionBuilder(this.fieldName).isNull()); }
887
+ isNotNull(): JoinBuilder<TParent> { return this.set(new FieldConditionBuilder(this.fieldName).isNotNull()); }
1047
888
  }
1048
889
 
1049
890
  /**