@umituz/react-native-firebase 2.6.1 → 2.6.3

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 (94) hide show
  1. package/package.json +1 -1
  2. package/src/application/auth/ports/AuthPort_part_aa +150 -0
  3. package/src/application/auth/ports/AuthPort_part_ab +14 -0
  4. package/src/application/auth/use-cases/SignInUseCaseHelpers.ts +0 -0
  5. package/src/application/auth/use-cases/SignInUseCaseMain.ts +0 -0
  6. package/src/application/auth/use-cases/SignInUseCase_part_aa +150 -0
  7. package/src/application/auth/use-cases/SignInUseCase_part_ab +103 -0
  8. package/src/application/auth/use-cases/SignOutUseCaseCleanup.ts +0 -0
  9. package/src/application/auth/use-cases/SignOutUseCaseMain.ts +0 -0
  10. package/src/application/auth/use-cases/SignOutUseCase_part_aa +150 -0
  11. package/src/application/auth/use-cases/SignOutUseCase_part_ab +138 -0
  12. package/src/domains/account-deletion/domain/services/UserValidationHelpers.ts.bak +181 -0
  13. package/src/domains/account-deletion/domain/services/UserValidationHelpers_part_aa +150 -0
  14. package/src/domains/account-deletion/domain/services/UserValidationHelpers_part_ab +31 -0
  15. package/src/domains/account-deletion/domain/services/{UserValidationService.ts → UserValidationService.ts.bak} +1 -10
  16. package/src/domains/account-deletion/domain/services/UserValidationService_part_aa +150 -0
  17. package/src/domains/account-deletion/domain/services/UserValidationService_part_ab +136 -0
  18. package/src/domains/account-deletion/infrastructure/services/AccountDeletionExecutor_part_aa +150 -0
  19. package/src/domains/account-deletion/infrastructure/services/AccountDeletionExecutor_part_ab +80 -0
  20. package/src/domains/account-deletion/infrastructure/services/AccountDeletionReauthHandler_part_aa +150 -0
  21. package/src/domains/account-deletion/infrastructure/services/AccountDeletionReauthHandler_part_ab +24 -0
  22. package/src/domains/account-deletion/infrastructure/services/AccountDeletionRepository_part_aa +150 -0
  23. package/src/domains/account-deletion/infrastructure/services/AccountDeletionRepository_part_ab +116 -0
  24. package/src/domains/account-deletion/infrastructure/services/reauthentication.service_part_aa +150 -0
  25. package/src/domains/account-deletion/infrastructure/services/reauthentication.service_part_ab +10 -0
  26. package/src/domains/auth/infrastructure_part_aa +150 -0
  27. package/src/domains/auth/infrastructure_part_ab +6 -0
  28. package/src/domains/auth/presentation/hooks/GoogleOAuthHelpers.ts +0 -0
  29. package/src/domains/auth/presentation/hooks/GoogleOAuthHookService_part_aa +150 -0
  30. package/src/domains/auth/presentation/hooks/GoogleOAuthHookService_part_ab +97 -0
  31. package/src/domains/auth/presentation/hooks/GoogleOAuthService.ts +0 -0
  32. package/src/domains/firestore/domain/entities/Collection.ts +31 -191
  33. package/src/domains/firestore/domain/entities/Collection.ts.bak +288 -0
  34. package/src/domains/firestore/domain/entities/CollectionFactory.ts +55 -0
  35. package/src/domains/firestore/domain/entities/CollectionHelpers.ts +143 -0
  36. package/src/domains/firestore/domain/entities/CollectionUtils.ts +72 -0
  37. package/src/domains/firestore/domain/entities/CollectionValidation.ts +138 -0
  38. package/src/domains/firestore/domain/entities/Collection_part_aa +150 -0
  39. package/src/domains/firestore/domain/entities/Collection_part_ab +138 -0
  40. package/src/domains/firestore/domain/entities/DocumentHelpers.ts +0 -0
  41. package/src/domains/firestore/domain/entities/DocumentMain.ts +0 -0
  42. package/src/domains/firestore/domain/entities/Document_part_aa +150 -0
  43. package/src/domains/firestore/domain/entities/Document_part_ab +83 -0
  44. package/src/domains/firestore/domain/index.ts +35 -8
  45. package/src/domains/firestore/domain/services/QueryServiceAnalysis_part_aa +150 -0
  46. package/src/domains/firestore/domain/services/QueryServiceAnalysis_part_ab +19 -0
  47. package/src/domains/firestore/domain/services/QueryServiceHelpers_part_aa +150 -0
  48. package/src/domains/firestore/domain/services/QueryServiceHelpers_part_ab +1 -0
  49. package/src/domains/firestore/domain/services/QueryService_part_aa +150 -0
  50. package/src/domains/firestore/domain/services/QueryService_part_ab +32 -0
  51. package/src/domains/firestore/domain/value-objects/QueryOptions.ts +20 -68
  52. package/src/domains/firestore/domain/value-objects/QueryOptions.ts.bak +6 -135
  53. package/src/domains/firestore/domain/value-objects/QueryOptionsFactory.ts +95 -0
  54. package/src/domains/firestore/domain/value-objects/QueryOptionsHelpers.ts +110 -0
  55. package/src/domains/firestore/domain/value-objects/QueryOptionsSerialization_part_aa +150 -0
  56. package/src/domains/firestore/domain/value-objects/QueryOptionsSerialization_part_ab +57 -0
  57. package/src/domains/firestore/domain/value-objects/QueryOptionsValidation_part_aa +150 -0
  58. package/src/domains/firestore/domain/value-objects/QueryOptionsValidation_part_ab +32 -0
  59. package/src/domains/firestore/domain/value-objects/QueryOptions_part_aa +150 -0
  60. package/src/domains/firestore/domain/value-objects/QueryOptions_part_ab +41 -0
  61. package/src/domains/firestore/domain/value-objects/WhereClause.ts +35 -205
  62. package/src/domains/firestore/domain/value-objects/WhereClause.ts.bak +299 -0
  63. package/src/domains/firestore/domain/value-objects/WhereClauseFactory.ts +44 -150
  64. package/src/domains/firestore/domain/value-objects/WhereClauseFactory.ts.bak +207 -0
  65. package/src/domains/firestore/domain/value-objects/WhereClauseFactory_part_aa +150 -0
  66. package/src/domains/firestore/domain/value-objects/WhereClauseFactory_part_ab +57 -0
  67. package/src/domains/firestore/domain/value-objects/WhereClauseHelpers.ts +123 -0
  68. package/src/domains/firestore/domain/value-objects/WhereClauseValidation.ts +83 -0
  69. package/src/domains/firestore/domain/value-objects/WhereClause_part_aa +150 -0
  70. package/src/domains/firestore/domain/value-objects/WhereClause_part_ab +149 -0
  71. package/src/shared/infrastructure/base/ErrorHandler_part_aa +150 -0
  72. package/src/shared/infrastructure/base/ErrorHandler_part_ab +39 -0
  73. package/src/shared/infrastructure/base/ServiceBase_part_aa +150 -0
  74. package/src/shared/infrastructure/base/ServiceBase_part_ab +70 -0
  75. package/src/shared/infrastructure/config/base/ServiceClientSingleton_part_aa +150 -0
  76. package/src/shared/infrastructure/config/base/ServiceClientSingleton_part_ab +5 -0
  77. /package/src/application/auth/ports/{AuthPort.ts → AuthPort.ts.bak} +0 -0
  78. /package/src/application/auth/use-cases/{SignInUseCase.ts → SignInUseCase.ts.bak} +0 -0
  79. /package/src/application/auth/use-cases/{SignOutUseCase.ts → SignOutUseCase.ts.bak} +0 -0
  80. /package/src/domains/account-deletion/infrastructure/services/{AccountDeletionExecutor.ts → AccountDeletionExecutor.ts.bak} +0 -0
  81. /package/src/domains/account-deletion/infrastructure/services/{AccountDeletionReauthHandler.ts → AccountDeletionReauthHandler.ts.bak} +0 -0
  82. /package/src/domains/account-deletion/infrastructure/services/{AccountDeletionRepository.ts → AccountDeletionRepository.ts.bak} +0 -0
  83. /package/src/domains/account-deletion/infrastructure/services/{reauthentication.service.ts → reauthentication.service.ts.bak} +0 -0
  84. /package/src/domains/auth/{infrastructure.ts → infrastructure.ts.bak} +0 -0
  85. /package/src/domains/auth/presentation/hooks/{GoogleOAuthHookService.ts → GoogleOAuthHookService.ts.bak} +0 -0
  86. /package/src/domains/firestore/domain/entities/{Document.ts → Document.ts.bak} +0 -0
  87. /package/src/domains/firestore/domain/services/{QueryService.ts → QueryService.ts.bak} +0 -0
  88. /package/src/domains/firestore/domain/services/{QueryServiceAnalysis.ts → QueryServiceAnalysis.ts.bak} +0 -0
  89. /package/src/domains/firestore/domain/services/{QueryServiceHelpers.ts → QueryServiceHelpers.ts.bak} +0 -0
  90. /package/src/domains/firestore/domain/value-objects/{QueryOptionsSerialization.ts → QueryOptionsSerialization.ts.bak} +0 -0
  91. /package/src/domains/firestore/domain/value-objects/{QueryOptionsValidation.ts → QueryOptionsValidation.ts.bak} +0 -0
  92. /package/src/shared/infrastructure/base/{ErrorHandler.ts → ErrorHandler.ts.bak} +0 -0
  93. /package/src/shared/infrastructure/base/{ServiceBase.ts → ServiceBase.ts.bak} +0 -0
  94. /package/src/shared/infrastructure/config/base/{ServiceClientSingleton.ts → ServiceClientSingleton.ts.bak} +0 -0
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Where Clause Value Object
2
+ * Where Clause Value Object (Main)
3
3
  * Single Responsibility: Encapsulate where clause conditions
4
4
  *
5
5
  * Value object that represents a single where clause condition.
@@ -9,6 +9,9 @@
9
9
  */
10
10
 
11
11
  import type { WhereFilterOp } from 'firebase/firestore';
12
+ import * as Validation from './WhereClauseValidation';
13
+ import * as Helpers from './WhereClauseHelpers';
14
+ import * as Factory from './WhereClauseFactory';
12
15
 
13
16
  /**
14
17
  * Valid where operators for Firestore queries
@@ -34,266 +37,93 @@ export class WhereClause {
34
37
  readonly operator: WhereFilterOp;
35
38
  readonly value: unknown;
36
39
 
37
- private constructor(field: string, operator: WhereFilterOp, value: unknown) {
40
+ constructor(field: string, operator: WhereFilterOp, value: unknown) {
38
41
  this.field = field;
39
42
  this.operator = operator;
40
43
  this.value = Object.freeze(value);
41
44
  }
42
45
 
43
- /**
44
- * Create a where clause
45
- */
46
- static create(field: string, operator: WhereFilterOp, value: unknown): WhereClause {
47
- return new WhereClause(field, operator, value);
48
- }
49
-
50
- /**
51
- * Create equality clause (==)
52
- */
53
- static equals(field: string, value: unknown): WhereClause {
54
- return new WhereClause(field, '==', value);
55
- }
56
-
57
- /**
58
- * Create inequality clause (!=)
59
- */
60
- static notEquals(field: string, value: unknown): WhereClause {
61
- return new WhereClause(field, '!=', value);
62
- }
63
-
64
- /**
65
- * Create less than clause (<)
66
- */
67
- static lessThan(field: string, value: unknown): WhereClause {
68
- return new WhereClause(field, '<', value);
69
- }
70
-
71
- /**
72
- * Create less than or equal clause (<=)
73
- */
74
- static lessThanOrEqual(field: string, value: unknown): WhereClause {
75
- return new WhereClause(field, '<=', value);
76
- }
77
-
78
- /**
79
- * Create greater than clause (>)
80
- */
81
- static greaterThan(field: string, value: unknown): WhereClause {
82
- return new WhereClause(field, '>', value);
83
- }
84
-
85
- /**
86
- * Create greater than or equal clause (>=)
87
- */
88
- static greaterThanOrEqual(field: string, value: unknown): WhereClause {
89
- return new WhereClause(field, '>=', value);
90
- }
91
-
92
- /**
93
- * Create array contains clause
94
- */
95
- static arrayContains(field: string, value: unknown): WhereClause {
96
- return new WhereClause(field, 'array-contains', value);
97
- }
98
-
99
- /**
100
- * Create array contains any clause
101
- */
102
- static arrayContainsAny(field: string, values: unknown[]): WhereClause {
103
- return new WhereClause(field, 'array-contains-any', values);
104
- }
105
-
106
- /**
107
- * Create in clause
108
- */
109
- static in(field: string, values: unknown[]): WhereClause {
110
- return new WhereClause(field, 'in', values);
111
- }
112
-
113
- /**
114
- * Create not-in clause
115
- */
116
- static notIn(field: string, values: unknown[]): WhereClause {
117
- return new WhereClause(field, 'not-in', values);
118
- }
119
-
120
- /**
121
- * Validate where clause
122
- */
46
+ // Instance methods using helpers
123
47
  validate(): { valid: boolean; errors: string[] } {
124
- const errors: string[] = [];
125
-
126
- // Validate field name
127
- if (!this.field || typeof this.field !== 'string' || this.field.trim() === '') {
128
- errors.push('Field name must be a non-empty string');
129
- }
130
-
131
- // Validate operator
132
- const validOperators: WhereFilterOp[] = [
133
- '==', '!=', '<', '<=', '>', '>=',
134
- 'array-contains', 'array-contains-any', 'in', 'not-in'
135
- ];
136
- if (!validOperators.includes(this.operator)) {
137
- errors.push(`Invalid operator: ${this.operator}`);
138
- }
139
-
140
- // Validate value based on operator
141
- if (this.operator === 'array-contains-any' || this.operator === 'in' || this.operator === 'not-in') {
142
- if (!Array.isArray(this.value)) {
143
- errors.push(`Operator ${this.operator} requires an array value`);
144
- } else if (this.value.length === 0) {
145
- errors.push(`Operator ${this.operator} requires a non-empty array`);
146
- } else if (this.value.length > 10) {
147
- errors.push(`Operator ${this.operator} supports maximum 10 elements`);
148
- }
149
- }
150
-
151
- return {
152
- valid: errors.length === 0,
153
- errors,
154
- };
48
+ return Validation.validateWhereClause(this);
155
49
  }
156
50
 
157
- /**
158
- * Check if equals another where clause
159
- */
160
51
  equals(other: WhereClause): boolean {
161
- return (
162
- this.field === other.field &&
163
- this.operator === other.operator &&
164
- JSON.stringify(this.value) === JSON.stringify(other.value)
165
- );
52
+ return Helpers.whereClausesEqual(this, other);
166
53
  }
167
54
 
168
- /**
169
- * Check if compatible for compound queries
170
- * Some operator combinations are not allowed in Firestore
171
- */
172
55
  isCompatibleWith(other: WhereClause): boolean {
173
- // Equality and inequality operators can be combined
174
- // Array operators and membership operators have restrictions
175
- if (
176
- (this.isArrayOperator() || this.isMembership()) &&
177
- (other.isArrayOperator() || other.isMembership())
178
- ) {
179
- // Only one array/membership clause per query
180
- return false;
181
- }
182
-
183
- return true;
56
+ return Helpers.areClausesCompatible(this, other);
184
57
  }
185
58
 
186
- /**
187
- * Get field path components
188
- * Returns array of field path segments (for nested fields)
189
- */
190
59
  getFieldPath(): string[] {
191
- return this.field.split('.');
60
+ return Helpers.getFieldPath(this);
192
61
  }
193
62
 
194
- /**
195
- * Check if field is nested (contains dots)
196
- */
197
63
  isNestedField(): boolean {
198
- return this.field.includes('.');
64
+ return Helpers.isNestedField(this);
199
65
  }
200
66
 
201
- /**
202
- * Get top-level field name
203
- */
204
67
  getTopLevelField(): string {
205
- return this.getFieldPath()[0];
68
+ return Helpers.getTopLevelField(this);
206
69
  }
207
70
 
208
- /**
209
- * Get human-readable description
210
- */
211
71
  getDescription(): string {
212
- const valueStr = Array.isArray(this.value)
213
- ? `[${this.value.map(v => JSON.stringify(v)).join(', ')}]`
214
- : JSON.stringify(this.value);
215
-
216
- return `${this.field} ${this.operator} ${valueStr}`;
72
+ return Helpers.getDescription(this);
217
73
  }
218
74
 
219
- /**
220
- * Convert to plain object (for serialization)
221
- */
222
75
  toObject(): { field: string; operator: WhereFilterOp; value: unknown } {
223
- return {
224
- field: this.field,
225
- operator: this.operator,
226
- value: this.value,
227
- };
76
+ return Helpers.toObject(this);
228
77
  }
229
78
 
230
- /**
231
- * Create from plain object
232
- */
233
- static fromObject(obj: { field: string; operator: WhereFilterOp; value: unknown }): WhereClause {
234
- return WhereClause.create(obj.field, obj.operator, obj.value);
235
- }
236
-
237
- /**
238
- * Clone with new value
239
- */
240
79
  withValue(newValue: unknown): WhereClause {
241
80
  return new WhereClause(this.field, this.operator, newValue);
242
81
  }
243
82
 
244
- /**
245
- * Clone with new field
246
- */
247
83
  withField(newField: string): WhereClause {
248
84
  return new WhereClause(newField, this.operator, this.value);
249
85
  }
250
86
 
251
- /**
252
- * Clone with new operator
253
- */
254
87
  withOperator(newOperator: WhereFilterOp): WhereClause {
255
88
  return new WhereClause(this.field, newOperator, this.value);
256
89
  }
257
90
 
258
- /**
259
- * Check if is equality operator
260
- */
261
91
  isEquality(): boolean {
262
- return this.operator === '==';
92
+ return Helpers.isEqualityClause(this);
263
93
  }
264
94
 
265
- /**
266
- * Check if is inequality operator
267
- */
268
95
  isInequality(): boolean {
269
- return this.operator === '!=';
96
+ return Helpers.isInequalityClause(this);
270
97
  }
271
98
 
272
- /**
273
- * Check if is comparison operator (<, <=, >, >=)
274
- */
275
99
  isComparison(): boolean {
276
- return ['<', '<=', '>', '>='].includes(this.operator);
100
+ return Helpers.isComparisonClause(this);
277
101
  }
278
102
 
279
- /**
280
- * Check if is array operator
281
- */
282
103
  isArrayOperator(): boolean {
283
- return ['array-contains', 'array-contains-any'].includes(this.operator);
104
+ return Helpers.isArrayClause(this);
284
105
  }
285
106
 
286
- /**
287
- * Check if is membership operator (in, not-in)
288
- */
289
107
  isMembership(): boolean {
290
- return ['in', 'not-in'].includes(this.operator);
108
+ return Helpers.isMembershipClause(this);
291
109
  }
292
110
 
293
- /**
294
- * Check if operator requires array value
295
- */
296
111
  requiresArrayValue(): boolean {
297
- return ['array-contains-any', 'in', 'not-in'].includes(this.operator);
112
+ return Validation.requiresArrayValue(this.operator);
298
113
  }
299
114
  }
115
+
116
+ // Re-export factory functions for backward compatibility
117
+ export const create = Factory.where;
118
+ export const equals = Factory.equals;
119
+ export const notEquals = Factory.notEquals;
120
+ export const lessThan = Factory.lessThan;
121
+ export const lessThanOrEqual = Factory.lessThanOrEqual;
122
+ export const greaterThan = Factory.greaterThan;
123
+ export const greaterThanOrEqual = Factory.greaterThanOrEqual;
124
+ export const arrayContains = Factory.arrayContains;
125
+ export const inOp = Factory.inOp;
126
+ export const notIn = Factory.notIn;
127
+ export const arrayContainsAny = Factory.arrayContainsAny;
128
+ export const where = Factory.where;
129
+ export const fromObject = Factory.fromObject;
@@ -0,0 +1,299 @@
1
+ /**
2
+ * Where Clause Value Object
3
+ * Single Responsibility: Encapsulate where clause conditions
4
+ *
5
+ * Value object that represents a single where clause condition.
6
+ * Provides validation and business logic for query filtering.
7
+ *
8
+ * Max lines: 150 (enforced for maintainability)
9
+ */
10
+
11
+ import type { WhereFilterOp } from 'firebase/firestore';
12
+
13
+ /**
14
+ * Valid where operators for Firestore queries
15
+ */
16
+ export type WhereOperator =
17
+ | '=='
18
+ | '!='
19
+ | '<'
20
+ | '<='
21
+ | '>'
22
+ | '>='
23
+ | 'array-contains'
24
+ | 'array-contains-any'
25
+ | 'in'
26
+ | 'not-in';
27
+
28
+ /**
29
+ * Where clause value object
30
+ * Immutable representation of a single query condition
31
+ */
32
+ export class WhereClause {
33
+ readonly field: string;
34
+ readonly operator: WhereFilterOp;
35
+ readonly value: unknown;
36
+
37
+ private constructor(field: string, operator: WhereFilterOp, value: unknown) {
38
+ this.field = field;
39
+ this.operator = operator;
40
+ this.value = Object.freeze(value);
41
+ }
42
+
43
+ /**
44
+ * Create a where clause
45
+ */
46
+ static create(field: string, operator: WhereFilterOp, value: unknown): WhereClause {
47
+ return new WhereClause(field, operator, value);
48
+ }
49
+
50
+ /**
51
+ * Create equality clause (==)
52
+ */
53
+ static equals(field: string, value: unknown): WhereClause {
54
+ return new WhereClause(field, '==', value);
55
+ }
56
+
57
+ /**
58
+ * Create inequality clause (!=)
59
+ */
60
+ static notEquals(field: string, value: unknown): WhereClause {
61
+ return new WhereClause(field, '!=', value);
62
+ }
63
+
64
+ /**
65
+ * Create less than clause (<)
66
+ */
67
+ static lessThan(field: string, value: unknown): WhereClause {
68
+ return new WhereClause(field, '<', value);
69
+ }
70
+
71
+ /**
72
+ * Create less than or equal clause (<=)
73
+ */
74
+ static lessThanOrEqual(field: string, value: unknown): WhereClause {
75
+ return new WhereClause(field, '<=', value);
76
+ }
77
+
78
+ /**
79
+ * Create greater than clause (>)
80
+ */
81
+ static greaterThan(field: string, value: unknown): WhereClause {
82
+ return new WhereClause(field, '>', value);
83
+ }
84
+
85
+ /**
86
+ * Create greater than or equal clause (>=)
87
+ */
88
+ static greaterThanOrEqual(field: string, value: unknown): WhereClause {
89
+ return new WhereClause(field, '>=', value);
90
+ }
91
+
92
+ /**
93
+ * Create array contains clause
94
+ */
95
+ static arrayContains(field: string, value: unknown): WhereClause {
96
+ return new WhereClause(field, 'array-contains', value);
97
+ }
98
+
99
+ /**
100
+ * Create array contains any clause
101
+ */
102
+ static arrayContainsAny(field: string, values: unknown[]): WhereClause {
103
+ return new WhereClause(field, 'array-contains-any', values);
104
+ }
105
+
106
+ /**
107
+ * Create in clause
108
+ */
109
+ static in(field: string, values: unknown[]): WhereClause {
110
+ return new WhereClause(field, 'in', values);
111
+ }
112
+
113
+ /**
114
+ * Create not-in clause
115
+ */
116
+ static notIn(field: string, values: unknown[]): WhereClause {
117
+ return new WhereClause(field, 'not-in', values);
118
+ }
119
+
120
+ /**
121
+ * Validate where clause
122
+ */
123
+ validate(): { valid: boolean; errors: string[] } {
124
+ const errors: string[] = [];
125
+
126
+ // Validate field name
127
+ if (!this.field || typeof this.field !== 'string' || this.field.trim() === '') {
128
+ errors.push('Field name must be a non-empty string');
129
+ }
130
+
131
+ // Validate operator
132
+ const validOperators: WhereFilterOp[] = [
133
+ '==', '!=', '<', '<=', '>', '>=',
134
+ 'array-contains', 'array-contains-any', 'in', 'not-in'
135
+ ];
136
+ if (!validOperators.includes(this.operator)) {
137
+ errors.push(`Invalid operator: ${this.operator}`);
138
+ }
139
+
140
+ // Validate value based on operator
141
+ if (this.operator === 'array-contains-any' || this.operator === 'in' || this.operator === 'not-in') {
142
+ if (!Array.isArray(this.value)) {
143
+ errors.push(`Operator ${this.operator} requires an array value`);
144
+ } else if (this.value.length === 0) {
145
+ errors.push(`Operator ${this.operator} requires a non-empty array`);
146
+ } else if (this.value.length > 10) {
147
+ errors.push(`Operator ${this.operator} supports maximum 10 elements`);
148
+ }
149
+ }
150
+
151
+ return {
152
+ valid: errors.length === 0,
153
+ errors,
154
+ };
155
+ }
156
+
157
+ /**
158
+ * Check if equals another where clause
159
+ */
160
+ equals(other: WhereClause): boolean {
161
+ return (
162
+ this.field === other.field &&
163
+ this.operator === other.operator &&
164
+ JSON.stringify(this.value) === JSON.stringify(other.value)
165
+ );
166
+ }
167
+
168
+ /**
169
+ * Check if compatible for compound queries
170
+ * Some operator combinations are not allowed in Firestore
171
+ */
172
+ isCompatibleWith(other: WhereClause): boolean {
173
+ // Equality and inequality operators can be combined
174
+ // Array operators and membership operators have restrictions
175
+ if (
176
+ (this.isArrayOperator() || this.isMembership()) &&
177
+ (other.isArrayOperator() || other.isMembership())
178
+ ) {
179
+ // Only one array/membership clause per query
180
+ return false;
181
+ }
182
+
183
+ return true;
184
+ }
185
+
186
+ /**
187
+ * Get field path components
188
+ * Returns array of field path segments (for nested fields)
189
+ */
190
+ getFieldPath(): string[] {
191
+ return this.field.split('.');
192
+ }
193
+
194
+ /**
195
+ * Check if field is nested (contains dots)
196
+ */
197
+ isNestedField(): boolean {
198
+ return this.field.includes('.');
199
+ }
200
+
201
+ /**
202
+ * Get top-level field name
203
+ */
204
+ getTopLevelField(): string {
205
+ return this.getFieldPath()[0];
206
+ }
207
+
208
+ /**
209
+ * Get human-readable description
210
+ */
211
+ getDescription(): string {
212
+ const valueStr = Array.isArray(this.value)
213
+ ? `[${this.value.map(v => JSON.stringify(v)).join(', ')}]`
214
+ : JSON.stringify(this.value);
215
+
216
+ return `${this.field} ${this.operator} ${valueStr}`;
217
+ }
218
+
219
+ /**
220
+ * Convert to plain object (for serialization)
221
+ */
222
+ toObject(): { field: string; operator: WhereFilterOp; value: unknown } {
223
+ return {
224
+ field: this.field,
225
+ operator: this.operator,
226
+ value: this.value,
227
+ };
228
+ }
229
+
230
+ /**
231
+ * Create from plain object
232
+ */
233
+ static fromObject(obj: { field: string; operator: WhereFilterOp; value: unknown }): WhereClause {
234
+ return WhereClause.create(obj.field, obj.operator, obj.value);
235
+ }
236
+
237
+ /**
238
+ * Clone with new value
239
+ */
240
+ withValue(newValue: unknown): WhereClause {
241
+ return new WhereClause(this.field, this.operator, newValue);
242
+ }
243
+
244
+ /**
245
+ * Clone with new field
246
+ */
247
+ withField(newField: string): WhereClause {
248
+ return new WhereClause(newField, this.operator, this.value);
249
+ }
250
+
251
+ /**
252
+ * Clone with new operator
253
+ */
254
+ withOperator(newOperator: WhereFilterOp): WhereClause {
255
+ return new WhereClause(this.field, newOperator, this.value);
256
+ }
257
+
258
+ /**
259
+ * Check if is equality operator
260
+ */
261
+ isEquality(): boolean {
262
+ return this.operator === '==';
263
+ }
264
+
265
+ /**
266
+ * Check if is inequality operator
267
+ */
268
+ isInequality(): boolean {
269
+ return this.operator === '!=';
270
+ }
271
+
272
+ /**
273
+ * Check if is comparison operator (<, <=, >, >=)
274
+ */
275
+ isComparison(): boolean {
276
+ return ['<', '<=', '>', '>='].includes(this.operator);
277
+ }
278
+
279
+ /**
280
+ * Check if is array operator
281
+ */
282
+ isArrayOperator(): boolean {
283
+ return ['array-contains', 'array-contains-any'].includes(this.operator);
284
+ }
285
+
286
+ /**
287
+ * Check if is membership operator (in, not-in)
288
+ */
289
+ isMembership(): boolean {
290
+ return ['in', 'not-in'].includes(this.operator);
291
+ }
292
+
293
+ /**
294
+ * Check if operator requires array value
295
+ */
296
+ requiresArrayValue(): boolean {
297
+ return ['array-contains-any', 'in', 'not-in'].includes(this.operator);
298
+ }
299
+ }