1- import type { JsonaryCondition , JsonaryParent } from '@interfaces/index .ts'
2- import { getOperatorsSorted , queryOperators } from '@root /Constant.ts'
1+ import type * as Types from '@app/Types .ts'
2+ import { getOperatorsSorted , queryOperators } from '@app /Constant.ts'
33
44/**
5- * Query builder for filtering and manipulating JSON data.
6- * @description Provides fluent interface for building complex queries with chaining operations .
5+ * Query builder for records
6+ * @description Fluent chaining for filters, updates, deletes .
77 */
88export class QueryBuilder {
99 /** Cache for recently parsed conditions to improve performance */
10- private static readonly conditionRecent : Map < string , JsonaryCondition | null > = new Map ( )
10+ private static readonly recentConditionCache : Map < string , Types . JsonaryCondition | null > =
11+ new Map ( )
1112 /** Parent instance for synchronization */
12- private readonly parent : JsonaryParent | undefined
13+ private readonly parentDb : Types . JsonaryParent | undefined
1314 /** Array of applied conditions */
14- private readonly conditions : JsonaryCondition [ ] = [ ]
15+ private readonly conditions : Types . JsonaryCondition [ ] = [ ]
1516 /** Original data array reference */
16- private readonly originalData : Record < string , unknown > [ ]
17+ private readonly originalRecords : Record < string , unknown > [ ]
1718 /** Current filtered data array */
18- private data : Record < string , unknown > [ ]
19+ private records : Record < string , unknown > [ ]
1920
2021 /**
21- * Creates a new QueryBuilder instance.
22- * @description Initializes the query builder with data and optional parent reference .
22+ * Create QueryBuilder instance
23+ * @description Stores records and optional parent sync .
2324 * @param data - Array of data records to query
2425 * @param parent - Optional parent instance for synchronization
2526 */
26- constructor ( data : Record < string , unknown > [ ] , parent ?: JsonaryParent ) {
27- this . originalData = data
28- this . data = [ ...data ]
29- this . parent = parent
27+ constructor ( data : Record < string , unknown > [ ] , parent ?: Types . JsonaryParent ) {
28+ this . originalRecords = data
29+ this . records = [ ...data ]
30+ this . parentDb = parent
3031 }
3132
3233 /**
33- * Gets the count of filtered records.
34- * @description Returns the number of records matching current filter conditions.
34+ * Count filtered records
35+ * @description Returns records matching current conditions.
3536 * @returns Number of matching records
3637 */
3738 count ( ) : number {
38- return this . data . length
39+ return this . records . length
3940 }
4041
4142 /**
42- * Deletes all filtered records.
43- * @description Removes all records matching current conditions from original data .
43+ * Delete filtered records
44+ * @description Removes matches from original records .
4445 * @returns Number of records deleted
4546 */
4647 delete ( ) : number {
47- const deletedCount : number = this . data . length
48- const itemsToDelete : Set < Record < string , unknown > > = new Set ( this . data )
49- for ( let i : number = this . originalData . length - 1 ; i >= 0 ; i -- ) {
50- if ( itemsToDelete . has ( this . originalData [ i ] as Record < string , unknown > ) ) {
51- this . originalData . splice ( i , 1 )
48+ const deletedCount : number = this . records . length
49+ const recordsToDelete : Set < Record < string , unknown > > = new Set ( this . records )
50+ for ( let i : number = this . originalRecords . length - 1 ; i >= 0 ; i -- ) {
51+ if ( recordsToDelete . has ( this . originalRecords [ i ] as Record < string , unknown > ) ) {
52+ this . originalRecords . splice ( i , 1 )
5253 }
5354 }
54- this . data . length = 0
55- this . parent ?. syncFromQueryBuilder ( this . originalData )
55+ this . records . length = 0
56+ this . parentDb ?. syncFromQueryBuilder ( this . originalRecords )
5657 return deletedCount
5758 }
5859
5960 /**
60- * Gets the first filtered record.
61- * @description Returns the first record matching current conditions or null if none found .
61+ * Get first filtered record
62+ * @description Returns first match, or null.
6263 * @returns First matching record or null
6364 */
6465 first ( ) : Record < string , unknown > | null {
65- return this . data [ 0 ] ?? null
66+ return this . records [ 0 ] ?? null
6667 }
6768
6869 /**
69- * Gets all filtered records.
70- * @description Returns a copy of all records matching current conditions .
70+ * Get filtered records
71+ * @description Returns copy of matching records .
7172 * @returns Array of matching records
7273 */
7374 get ( ) : Record < string , unknown > [ ] {
74- return [ ...this . data ]
75+ return [ ...this . records ]
7576 }
7677
7778 /**
78- * Updates all filtered records.
79- * @description Applies the provided data to all records matching current conditions .
79+ * Update filtered records
80+ * @description Applies fields to all matches .
8081 * @param data - Object containing fields to update
8182 */
8283 update ( data : Record < string , unknown > ) : void {
83- this . data . forEach ( ( item : Record < string , unknown > ) => {
84+ this . records . forEach ( ( item : Record < string , unknown > ) => {
8485 Object . keys ( data ) . forEach ( ( key : string ) => {
8586 if ( key . includes ( '.' ) ) {
8687 this . setNestedValue ( item , key , data [ key ] )
@@ -89,42 +90,45 @@ export class QueryBuilder {
8990 }
9091 } )
9192 } )
92- this . parent ?. syncFromQueryBuilder ( this . originalData )
93+ this . parentDb ?. syncFromQueryBuilder ( this . originalRecords )
9394 }
9495
9596 /**
96- * Adds a filter condition to the query.
97- * @description Filters records based on string condition or function predicate.
97+ * Add filter condition
98+ * @description Filters by string or predicate.
9899 * @param condition - Query string or function to filter records
99100 * @returns QueryBuilder instance for chaining
100101 */
101102 where ( condition : string | ( ( item : Record < string , unknown > ) => boolean ) ) : QueryBuilder {
102103 if ( typeof condition === 'function' ) {
103- this . data = this . data . filter ( condition )
104+ this . records = this . records . filter ( condition )
104105 } else {
105- const parsed : JsonaryCondition | null = this . parseCondition ( condition )
106- if ( parsed ) {
107- this . conditions . push ( parsed )
108- this . data = this . data . filter ( ( item : Record < string , unknown > ) =>
109- this . evaluateCondition ( item , parsed )
106+ const parsedCondition : Types . JsonaryCondition | null = this . parseCondition ( condition )
107+ if ( parsedCondition ) {
108+ this . conditions . push ( parsedCondition )
109+ this . records = this . records . filter ( ( item : Record < string , unknown > ) =>
110+ this . evaluateCondition ( item , parsedCondition )
110111 )
111112 }
112113 }
113114 return this
114115 }
115116
116117 /**
117- * Evaluates a condition against a data item.
118- * @description Checks if an item matches the specified condition using appropriate operator.
118+ * Evaluate condition against item
119+ * @description Checks item match for given operator.
119120 * @param item - Data item to evaluate
120121 * @param condition - Condition to check against
121122 * @returns True if condition matches, false otherwise
122123 */
123- private evaluateCondition ( item : Record < string , unknown > , condition : JsonaryCondition ) : boolean {
124- const { operator, value } : JsonaryCondition = condition
124+ private evaluateCondition (
125+ item : Record < string , unknown > ,
126+ condition : Types . JsonaryCondition
127+ ) : boolean {
128+ const { operator, value } : Types . JsonaryCondition = condition
125129 const fieldValue : unknown = this . getNestedValue ( item , condition . field )
126- const op : JsonaryCondition [ 'operator' ] = operator
127- switch ( op ) {
130+ const operatorToken : Types . JsonaryCondition [ 'operator' ] = operator
131+ switch ( operatorToken ) {
128132 case queryOperators . eq :
129133 return fieldValue === value
130134 case queryOperators . neq :
@@ -157,8 +161,8 @@ export class QueryBuilder {
157161 }
158162
159163 /**
160- * Gets a nested value from an object using dot notation.
161- * @description Traverses object properties using dot-separated path.
164+ * Get nested value by path
165+ * @description Traverses dot-separated property path.
162166 * @param obj - Object to traverse
163167 * @param path - Dot-separated path to the property
164168 * @returns Value at the specified path or undefined
@@ -167,53 +171,53 @@ export class QueryBuilder {
167171 if ( ! path . includes ( '.' ) ) {
168172 return obj [ path ]
169173 }
170- let current : unknown = obj
174+ let currentValue : unknown = obj
171175 const keys : string [ ] = path . split ( '.' )
172176 for ( let i : number = 0 ; i < keys . length ; i ++ ) {
173- if ( current === null || current === undefined || typeof current !== 'object' ) {
177+ if ( currentValue === null || currentValue === undefined || typeof currentValue !== 'object' ) {
174178 return undefined
175179 }
176180 const key : string | undefined = keys [ i ]
177181 if ( key === undefined ) {
178182 return undefined
179183 }
180- current = ( current as Record < string , unknown > ) [ key ]
184+ currentValue = ( currentValue as Record < string , unknown > ) [ key ]
181185 }
182- return current
186+ return currentValue
183187 }
184188
185189 /**
186- * Parses a string condition into structured format.
187- * @description Converts string-based conditions into JsonaryCondition objects .
190+ * Parse condition string
191+ * @description Converts string to condition object .
188192 * @param condition - String condition to parse
189193 * @returns Parsed condition object or null if invalid
190194 */
191- private parseCondition ( condition : string ) : JsonaryCondition | null {
192- if ( QueryBuilder . conditionRecent . has ( condition ) ) {
193- return QueryBuilder . conditionRecent . get ( condition ) ?? null
195+ private parseCondition ( condition : string ) : Types . JsonaryCondition | null {
196+ if ( QueryBuilder . recentConditionCache . has ( condition ) ) {
197+ return QueryBuilder . recentConditionCache . get ( condition ) ?? null
194198 }
195199 const operators : string [ ] = getOperatorsSorted ( )
196- for ( const op of operators ) {
197- const index : number = condition . indexOf ( op )
200+ for ( const operatorToken of operators ) {
201+ const index : number = condition . indexOf ( operatorToken )
198202 if ( index !== - 1 ) {
199- const value : string = condition . substring ( index + op . length ) . trim ( )
200- const parsedValue : unknown = this . parseSpecialValue ( this . stripQuotes ( value ) )
201- const result : JsonaryCondition = {
203+ const rawValue : string = condition . substring ( index + operatorToken . length ) . trim ( )
204+ const parsedValue : unknown = this . parseSpecialValue ( this . stripQuotes ( rawValue ) )
205+ const result : Types . JsonaryCondition = {
202206 field : condition . substring ( 0 , index ) . trim ( ) ,
203- operator : op as JsonaryCondition [ 'operator' ] ,
207+ operator : operatorToken as Types . JsonaryCondition [ 'operator' ] ,
204208 value : parsedValue
205209 }
206- QueryBuilder . conditionRecent . set ( condition , result )
210+ QueryBuilder . recentConditionCache . set ( condition , result )
207211 return result
208212 }
209213 }
210- QueryBuilder . conditionRecent . set ( condition , null )
214+ QueryBuilder . recentConditionCache . set ( condition , null )
211215 return null
212216 }
213217
214218 /**
215- * Parses special string values to their appropriate types.
216- * @description Converts string representations of special values to their actual types .
219+ * Parse special value tokens
220+ * @description Converts tokens to typed values .
217221 * @param value - Value to parse
218222 * @returns Parsed value in appropriate type
219223 */
@@ -236,34 +240,38 @@ export class QueryBuilder {
236240 }
237241
238242 /**
239- * Sets a nested value in an object using dot notation.
240- * @description Creates nested objects as needed and sets the final value.
243+ * Set nested value by path
244+ * @description Creates objects and sets final value.
241245 * @param obj - Object to modify
242246 * @param path - Dot-separated path to the property
243247 * @param value - Value to set
244248 */
245249 private setNestedValue ( obj : Record < string , unknown > , path : string , value : unknown ) : void {
246250 const keys : string [ ] = path . split ( '.' )
247- let current : Record < string , unknown > = obj
251+ let currentObject : Record < string , unknown > = obj
248252 for ( let i : number = 0 ; i < keys . length - 1 ; i ++ ) {
249253 const key : string | undefined = keys [ i ]
250254 if ( key === undefined ) {
251255 continue
252256 }
253- if ( ! ( key in current ) || typeof current [ key ] !== 'object' || current [ key ] === null ) {
254- current [ key ] = { }
257+ if (
258+ ! ( key in currentObject ) ||
259+ typeof currentObject [ key ] !== 'object' ||
260+ currentObject [ key ] === null
261+ ) {
262+ currentObject [ key ] = { }
255263 }
256- current = current [ key ] as Record < string , unknown >
264+ currentObject = currentObject [ key ] as Record < string , unknown >
257265 }
258266 const lastKey : string | undefined = keys [ keys . length - 1 ]
259267 if ( lastKey !== undefined ) {
260- current [ lastKey ] = value
268+ currentObject [ lastKey ] = value
261269 }
262270 }
263271
264272 /**
265- * Strips quotes from string values.
266- * @description Removes surrounding single or double quotes from string values .
273+ * Strip surrounding quotes
274+ * @description Removes wrapping single or double quotes.
267275 * @param value - String value to process
268276 * @returns Processed value with quotes removed if applicable
269277 */
0 commit comments