masterrecord 0.2.36 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/.claude/settings.local.json +20 -1
  2. package/Entity/entityModel.js +6 -0
  3. package/Entity/entityTrackerModel.js +20 -3
  4. package/Entity/fieldTransformer.js +266 -0
  5. package/Migrations/migrationMySQLQuery.js +145 -1
  6. package/Migrations/migrationPostgresQuery.js +402 -0
  7. package/Migrations/migrationSQLiteQuery.js +145 -1
  8. package/Migrations/schema.js +131 -28
  9. package/QueryLanguage/queryMethods.js +193 -15
  10. package/QueryLanguage/queryParameters.js +136 -0
  11. package/QueryLanguage/queryScript.js +13 -4
  12. package/SQLLiteEngine.js +331 -20
  13. package/context.js +91 -14
  14. package/docs/INCLUDES_CLARIFICATION.md +202 -0
  15. package/docs/METHODS_REFERENCE.md +184 -0
  16. package/docs/MIGRATIONS_GUIDE.md +699 -0
  17. package/docs/POSTGRESQL_SETUP.md +415 -0
  18. package/examples/jsonArrayTransformer.js +215 -0
  19. package/mySQLEngine.js +273 -17
  20. package/package.json +3 -3
  21. package/postgresEngine.js +600 -483
  22. package/postgresSyncConnect.js +209 -0
  23. package/readme.md +1046 -416
  24. package/test/anyCommaStringTest.js +237 -0
  25. package/test/anyMethodTest.js +176 -0
  26. package/test/findByIdTest.js +227 -0
  27. package/test/includesFeatureTest.js +183 -0
  28. package/test/includesTransformTest.js +110 -0
  29. package/test/newMethodTest.js +330 -0
  30. package/test/newMethodUnitTest.js +320 -0
  31. package/test/parameterizedPlaceholderTest.js +159 -0
  32. package/test/postgresEngineTest.js +463 -0
  33. package/test/postgresIntegrationTest.js +381 -0
  34. package/test/securityTest.js +268 -0
  35. package/test/singleDollarPlaceholderTest.js +238 -0
  36. package/test/transformerTest.js +287 -0
  37. package/test/verifyFindById.js +169 -0
  38. package/test/verifyNewMethod.js +191 -0
package/context.js CHANGED
@@ -5,6 +5,7 @@ var query = require('masterrecord/QueryLanguage/queryMethods');
5
5
  var tools = require('./Tools');
6
6
  var SQLLiteEngine = require('masterrecord/SQLLiteEngine');
7
7
  var MYSQLEngine = require('masterrecord/mySQLEngine');
8
+ var PostgresEngine = require('masterrecord/postgresEngine');
8
9
  var insertManager = require('./insertManager');
9
10
  var deleteManager = require('./deleteManager');
10
11
  var globSearch = require("glob");
@@ -12,6 +13,7 @@ var fs = require('fs');
12
13
  var path = require('path');
13
14
  const appRoot = require('app-root-path');
14
15
  const MySQLClient = require('masterrecord/mySQLSyncConnect');
16
+ const PostgresClient = require('masterrecord/postgresSyncConnect');
15
17
 
16
18
  class context {
17
19
  _isModelValid = {
@@ -72,7 +74,7 @@ class context {
72
74
  */
73
75
  __mysqlInit(env, sqlName){
74
76
  try{
75
-
77
+
76
78
  //const mysql = require(sqlName);
77
79
  const connection = new MySQLClient(env);
78
80
  this._SQLEngine = new MYSQLEngine();
@@ -85,6 +87,31 @@ class context {
85
87
  }
86
88
  }
87
89
 
90
+ /*
91
+ postgres expected model
92
+ {
93
+ "type": "postgres",
94
+ host : 'localhost',
95
+ port : 5432,
96
+ user : 'me',
97
+ password : 'secret',
98
+ database : 'my_db'
99
+ }
100
+ */
101
+ async __postgresInit(env, sqlName){
102
+ try{
103
+ const connection = new PostgresClient();
104
+ await connection.connect(env);
105
+ this._SQLEngine = connection.getEngine();
106
+ this._SQLEngine.__name = sqlName;
107
+ return connection.getPool();
108
+ }
109
+ catch (e) {
110
+ console.log("error PostgreSQL", e);
111
+ throw e;
112
+ }
113
+ }
114
+
88
115
  __clearErrorHandler(){
89
116
  this._isModelValid = {
90
117
  isValid: true,
@@ -212,13 +239,23 @@ class context {
212
239
  }
213
240
 
214
241
  if(type === 'mysql'){
215
- this.isMySQL = true; this.isSQLite = false;
242
+ this.isMySQL = true; this.isSQLite = false; this.isPostgres = false;
216
243
  this.db = this.__mysqlInit(options, 'mysql2');
217
244
  this._SQLEngine.setDB(this.db, 'mysql');
218
245
  return this;
219
246
  }
220
247
 
221
- throw new Error(`Unsupported database type '${options.type}'. Expected 'sqlite' or 'mysql'.`);
248
+ if(type === 'postgres' || type === 'postgresql'){
249
+ this.isPostgres = true; this.isMySQL = false; this.isSQLite = false;
250
+ // Postgres is async, so we need to handle promises
251
+ (async () => {
252
+ this.db = await this.__postgresInit(options, 'pg');
253
+ // Note: engine is already set in __postgresInit
254
+ })();
255
+ return this;
256
+ }
257
+
258
+ throw new Error(`Unsupported database type '${options.type}'. Expected 'sqlite', 'mysql', or 'postgres'.`);
222
259
  }
223
260
  catch(err){
224
261
  console.log("error:", err);
@@ -385,9 +422,9 @@ class context {
385
422
  break;
386
423
  case "modified":
387
424
  if(currentModel.__dirtyFields.length > 0){
388
- var cleanCurrentModel = tools.removePrimarykeyandVirtual(currentModel, currentModel._entity);
389
- // build columns equal to value string
390
- var argu = this._SQLEngine._buildSQLEqualTo(cleanCurrentModel);
425
+ var cleanCurrentModel = tools.removePrimarykeyandVirtual(currentModel, currentModel._entity);
426
+ // Use NEW SECURE parameterized version
427
+ var argu = this._SQLEngine._buildSQLEqualToParameterized(cleanCurrentModel);
391
428
  if(argu !== -1 ){
392
429
  var primaryKey = tools.getPrimaryKeyObject(cleanCurrentModel.__entity);
393
430
  var sqlUpdate = {tableName: cleanCurrentModel.__entity.__name, arg: argu, primaryKey : primaryKey, primaryKeyValue : cleanCurrentModel[primaryKey] };
@@ -396,7 +433,7 @@ class context {
396
433
  else{
397
434
  console.log("Nothing has been tracked, modified, created or added");
398
435
  }
399
-
436
+
400
437
  }
401
438
  else{
402
439
  console.log("Tracked entity modified with no values being changed");
@@ -419,16 +456,16 @@ class context {
419
456
  for (var model in tracked) {
420
457
  var currentModel = tracked[model];
421
458
  switch(currentModel.__state) {
422
- case "insert":
459
+ case "insert":
423
460
  var insert = new insertManager(this._SQLEngine, this._isModelValid, this.__entities);
424
461
  insert.init(currentModel);
425
-
462
+
426
463
  break;
427
464
  case "modified":
428
465
  if(currentModel.__dirtyFields.length > 0){
429
466
  var cleanCurrentModel = tools.removePrimarykeyandVirtual(currentModel, currentModel._entity);
430
- // build columns equal to value string
431
- var argu = this._SQLEngine._buildSQLEqualTo(cleanCurrentModel);
467
+ // Use NEW SECURE parameterized version
468
+ var argu = this._SQLEngine._buildSQLEqualToParameterized(cleanCurrentModel);
432
469
  if(argu !== -1 ){
433
470
  var primaryKey = tools.getPrimaryKeyObject(cleanCurrentModel.__entity);
434
471
  var sqlUpdate = {tableName: cleanCurrentModel.__entity.__name, arg: argu, primaryKey : primaryKey, primaryKeyValue : cleanCurrentModel[primaryKey] };
@@ -437,7 +474,7 @@ class context {
437
474
  else{
438
475
  console.log("Nothing has been tracked, modified, created or added");
439
476
  }
440
-
477
+
441
478
  }
442
479
  else{
443
480
  console.log("Tracked entity modified with no values being changed");
@@ -448,13 +485,53 @@ class context {
448
485
  case "delete":
449
486
  var deleteObject = new deleteManager(this._SQLEngine, this.__entities);
450
487
  deleteObject.init(currentModel);
451
-
488
+
452
489
  break;
453
- }
490
+ }
454
491
  }
455
492
  this.__clearErrorHandler();
456
493
  //this._SQLEngine.endTransaction();
457
494
  }
495
+ if(this.isPostgres){
496
+ // PostgreSQL async operations (no transaction control here)
497
+ for (var model in tracked) {
498
+ var currentModel = tracked[model];
499
+ switch(currentModel.__state) {
500
+ case "insert":
501
+ var insert = new insertManager(this._SQLEngine, this._isModelValid, this.__entities);
502
+ insert.init(currentModel);
503
+
504
+ break;
505
+ case "modified":
506
+ if(currentModel.__dirtyFields.length > 0){
507
+ var cleanCurrentModel = tools.removePrimarykeyandVirtual(currentModel, currentModel._entity);
508
+ // Use NEW SECURE parameterized version
509
+ var argu = this._SQLEngine._buildSQLEqualToParameterized(cleanCurrentModel);
510
+ if(argu !== -1 ){
511
+ var primaryKey = tools.getPrimaryKeyObject(cleanCurrentModel.__entity);
512
+ var sqlUpdate = {tableName: cleanCurrentModel.__entity.__name, arg: argu, primaryKey : primaryKey, primaryKeyValue : cleanCurrentModel[primaryKey] };
513
+ this._SQLEngine.update(sqlUpdate);
514
+ }
515
+ else{
516
+ console.log("Nothing has been tracked, modified, created or added");
517
+ }
518
+
519
+ }
520
+ else{
521
+ console.log("Tracked entity modified with no values being changed");
522
+ }
523
+
524
+ // code block
525
+ break;
526
+ case "delete":
527
+ var deleteObject = new deleteManager(this._SQLEngine, this.__entities);
528
+ deleteObject.init(currentModel);
529
+
530
+ break;
531
+ }
532
+ }
533
+ this.__clearErrorHandler();
534
+ }
458
535
  }
459
536
  else{
460
537
  console.log("save changes has no tracked entities");
@@ -0,0 +1,202 @@
1
+ # .includes() Syntax Clarification
2
+
3
+ ## Common Confusion: Two Different `.includes()` Methods
4
+
5
+ There are **two different** `.includes()` methods that developers confuse:
6
+
7
+ ### 1. JavaScript's Native `.includes()` ❌ NOT SUPPORTED
8
+ ```javascript
9
+ // ❌ WRONG - This is JavaScript's array.includes()
10
+ const ids = [1, 2, 3];
11
+ context.User.where(u => ids.includes(u.id)).toList();
12
+ // ^^^ JavaScript variable reference
13
+ ```
14
+
15
+ **Why it doesn't work:**
16
+ - The lambda `u => ...` is parsed as a **string**, not executed as JavaScript
17
+ - Cannot access JavaScript variables (`ids`) from inside the lambda string
18
+ - Cannot call JavaScript methods on those variables
19
+
20
+ **Error:**
21
+ ```
22
+ ReferenceError: ids is not defined
23
+ ```
24
+
25
+ ---
26
+
27
+ ### 2. MasterRecord's `.includes()` ✅ FULLY SUPPORTED
28
+ ```javascript
29
+ // ✅ CORRECT - This is MasterRecord's special syntax
30
+ const ids = [1, 2, 3];
31
+ context.User.where(u => $$.includes(u.id), ids).toList();
32
+ // ^^ MasterRecord placeholder
33
+ // ^^^ Pass array as argument
34
+ ```
35
+
36
+ **Why it works:**
37
+ - `$$` is a **placeholder** that MasterRecord recognizes
38
+ - The array `ids` is passed as a **separate argument**
39
+ - MasterRecord transforms `$$.includes(u.id)` → `u.id.any($$)` internally
40
+ - Generates proper SQL: `WHERE id IN (?, ?, ?)`
41
+
42
+ **Generated SQL:**
43
+ ```sql
44
+ SELECT * FROM User WHERE id IN (?, ?, ?)
45
+ -- Parameters: [1, 2, 3]
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Side-by-Side Comparison
51
+
52
+ | Feature | JavaScript `.includes()` | MasterRecord `.includes()` |
53
+ |---------|-------------------------|---------------------------|
54
+ | Syntax | `array.includes(field)` | `$$.includes(field)` |
55
+ | Where used | JavaScript code | MasterRecord lambda strings |
56
+ | Array location | Inside lambda | Separate argument |
57
+ | Supported | ❌ No | ✅ Yes |
58
+
59
+ ---
60
+
61
+ ## Examples: Wrong vs Right
62
+
63
+ ### ❌ Wrong: JavaScript Syntax
64
+ ```javascript
65
+ // Trying to use JavaScript's includes() - WON'T WORK
66
+ const userIds = [1, 2, 3];
67
+ const roleIds = [10, 20];
68
+
69
+ // ❌ Wrong
70
+ context.User
71
+ .where(u => userIds.includes(u.id) && roleIds.includes(u.role_id))
72
+ .toList();
73
+
74
+ // Error: userIds is not defined
75
+ ```
76
+
77
+ ### ✅ Right: MasterRecord Syntax
78
+ ```javascript
79
+ // Using MasterRecord's includes() - WORKS
80
+ const userIds = [1, 2, 3];
81
+ const roleIds = [10, 20];
82
+
83
+ // ✅ Correct
84
+ context.User
85
+ .where(u => $$.includes(u.id), userIds)
86
+ .and(u => $$.includes(u.role_id), roleIds)
87
+ .toList();
88
+
89
+ // Generates: WHERE id IN (?, ?, ?) AND role_id IN (?, ?)
90
+ // Params: [1, 2, 3, 10, 20]
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Alternative Syntax: `.any()`
96
+
97
+ You can also use `.any()` directly (it's what `.includes()` transforms to):
98
+
99
+ ```javascript
100
+ // Option 1: .includes() (modern, readable)
101
+ context.User.where(u => $$.includes(u.id), [1, 2, 3]).toList();
102
+
103
+ // Option 2: .any() (classic syntax)
104
+ context.User.where(u => u.id.any($$), [1, 2, 3]).toList();
105
+
106
+ // Option 3: .any() with comma string (also works)
107
+ context.User.where(u => u.id.any($$), "1,2,3").toList();
108
+
109
+ // All three generate the same SQL:
110
+ // WHERE id IN (?, ?, ?)
111
+ // Params: [1, 2, 3]
112
+ ```
113
+
114
+ ---
115
+
116
+ ## Why The Lambda is a String
117
+
118
+ MasterRecord's lambda expressions are **not executed as JavaScript**. They are:
119
+
120
+ 1. **Converted to strings**: `r => r.id == $` becomes the string `"r => r.id == $"`
121
+ 2. **Parsed**: MasterRecord extracts entity name (`r`), field name (`id`), operator (`==`), placeholder (`$`)
122
+ 3. **Converted to SQL**: Generates `WHERE id = ?`
123
+
124
+ **This means:**
125
+ - ✅ Can use: MasterRecord syntax (`$$`, `$`, `.any()`, `.includes()`, `.like()`)
126
+ - ❌ Cannot use: JavaScript variables, JavaScript methods, JavaScript operators beyond basic comparison
127
+
128
+ ---
129
+
130
+ ## Common Mistakes and Solutions
131
+
132
+ ### Mistake 1: Referencing JavaScript Variables
133
+ ```javascript
134
+ // ❌ Wrong
135
+ const minAge = 18;
136
+ context.User.where(u => u.age > minAge).toList();
137
+ // Error: minAge is not defined
138
+
139
+ // ✅ Right
140
+ const minAge = 18;
141
+ context.User.where(u => u.age > $, minAge).toList();
142
+ ```
143
+
144
+ ### Mistake 2: Using JavaScript Array Methods
145
+ ```javascript
146
+ // ❌ Wrong
147
+ const ids = [1, 2, 3];
148
+ context.User.where(u => ids.includes(u.id)).toList();
149
+ // Error: ids is not defined
150
+
151
+ // ✅ Right
152
+ const ids = [1, 2, 3];
153
+ context.User.where(u => $$.includes(u.id), ids).toList();
154
+ ```
155
+
156
+ ### Mistake 3: Calling JavaScript String Methods
157
+ ```javascript
158
+ // ❌ Wrong
159
+ context.User.where(u => u.name.startsWith("John")).toList();
160
+ // Error: startsWith is not defined
161
+
162
+ // ✅ Right - Use SQL LIKE
163
+ context.User.where(u => u.name.like($$), "John%").toList();
164
+ ```
165
+
166
+ ---
167
+
168
+ ## Quick Reference
169
+
170
+ **When writing MasterRecord queries:**
171
+
172
+ ✅ **DO use:**
173
+ - `$$` - Placeholder for parameters
174
+ - `$` - Single placeholder (backwards compatibility)
175
+ - `$$.includes(field)` - IN clause with arrays
176
+ - `field.any($$)` - Alternative IN clause syntax
177
+ - `field.like($$)` - LIKE clause
178
+ - Basic operators: `==`, `!=`, `>`, `<`, `>=`, `<=`, `&&`, `||`
179
+
180
+ ❌ **DON'T use:**
181
+ - JavaScript variables directly (use `$$` placeholders instead)
182
+ - JavaScript methods (`.includes()`, `.startsWith()`, etc.)
183
+ - Complex JavaScript expressions
184
+
185
+ ---
186
+
187
+ ## Summary
188
+
189
+ **MasterRecord's `.includes()` is fully supported and works great!**
190
+
191
+ Just remember:
192
+ 1. Use `$$.includes(field)` not `array.includes(field)`
193
+ 2. Pass the array as a separate argument
194
+ 3. The lambda is a string, not JavaScript code
195
+
196
+ **Correct Pattern:**
197
+ ```javascript
198
+ const values = [1, 2, 3];
199
+ context.Model.where(m => $$.includes(m.field), values).toList();
200
+ ```
201
+
202
+ This is **not a bug** - it's working as designed. The confusion comes from developers trying to use JavaScript's native `.includes()` method inside the lambda string, which isn't possible because lambdas are parsed, not executed.
@@ -0,0 +1,184 @@
1
+ # MasterRecord Methods Reference
2
+
3
+ ## Common Confusion: Dbset Methods vs Lambda Functions
4
+
5
+ MasterRecord has two types of methods that are often confused:
6
+
7
+ ### 1. Dbset Methods (Called on context.EntityName)
8
+
9
+ These are methods you call **directly on the dbset**:
10
+
11
+ ```javascript
12
+ const user = context.User.new(); // ✅ Dbset method
13
+ context.User.add(user); // ✅ Dbset method
14
+ context.User.where(u => u.id == $, 1); // ✅ Dbset method
15
+ context.User.toList(); // ✅ Dbset method
16
+ context.User.single(); // ✅ Dbset method
17
+ context.User.remove(user); // ✅ Dbset method
18
+ ```
19
+
20
+ **Location**: `QueryLanguage/queryMethods.js`
21
+
22
+ ### 2. Lambda Expression Functions (Used inside WHERE/AND clauses)
23
+
24
+ These are **functions used INSIDE the lambda expression string**:
25
+
26
+ ```javascript
27
+ // ✅ .any() - Used inside lambda
28
+ context.User.where(u => u.id.any($$), "1,2,3").toList();
29
+
30
+ // ✅ .like() - Used inside lambda
31
+ context.User.where(u => u.name.like($$), "John%").toList();
32
+
33
+ // ✅ .includes() - Used inside lambda (transforms to .any())
34
+ context.User.where(u => $$.includes(u.id), [1, 2, 3]).toList();
35
+ ```
36
+
37
+ **Location**: `QueryLanguage/queryScript.js` (parsed from lambda string)
38
+
39
+ ---
40
+
41
+ ## Complete Method List
42
+
43
+ ### Dbset Methods
44
+
45
+ | Method | Description | Example |
46
+ |--------|-------------|---------|
47
+ | `.new()` | Create new entity instance | `const user = context.User.new();` |
48
+ | `.add(entity)` | Track entity for INSERT | `context.User.add(user);` |
49
+ | `.remove(entity)` | Track entity for DELETE | `context.User.remove(user);` |
50
+ | `.where(lambda, ...args)` | Filter query | `context.User.where(u => u.id == $, 1)` |
51
+ | `.and(lambda, ...args)` | Add AND condition | `.where(...).and(u => u.active == true)` |
52
+ | `.orderBy(lambda)` | Sort ascending | `.orderBy(u => u.name)` |
53
+ | `.orderByDescending(lambda)` | Sort descending | `.orderByDescending(u => u.created_at)` |
54
+ | `.take(n)` | Limit results | `.take(10)` |
55
+ | `.skip(n)` | Offset results | `.skip(20)` |
56
+ | `.toList()` | Execute and return array | `.where(...).toList()` |
57
+ | `.single()` | Execute and return one | `.where(...).single()` |
58
+ | `.first()` | Execute and return first | `.where(...).first()` |
59
+ | `.include(lambda)` | Eager load relationships | `.include(u => u.Posts)` |
60
+ | `.raw(sql)` | Execute raw SQL | `.raw("SELECT * FROM User")` |
61
+
62
+ ### Lambda Expression Functions
63
+
64
+ | Function | Used Inside | Description | Example |
65
+ |----------|-------------|-------------|---------|
66
+ | `.any($$)` | WHERE/AND | IN clause (comma-separated) | `u => u.id.any($$), "1,2,3"` |
67
+ | `.like($$)` | WHERE/AND | LIKE clause | `u => u.name.like($$), "John%"` |
68
+ | `.includes()` | WHERE/AND | IN clause (array) | `$$.includes(u.id), [1,2,3]` |
69
+
70
+ ---
71
+
72
+ ## Common Patterns
73
+
74
+ ### Creating and Inserting Entities
75
+
76
+ ```javascript
77
+ // Create new entity
78
+ const user = context.User.new();
79
+ user.name = "John Doe";
80
+ user.email = "john@example.com";
81
+ user.age = 30;
82
+
83
+ // Track for insert
84
+ context.User.add(user); // Optional - .new() auto-tracks
85
+
86
+ // Save to database
87
+ context.saveChanges();
88
+ ```
89
+
90
+ ### IN Clause Queries
91
+
92
+ ```javascript
93
+ // Option 1: .any() with comma-separated string
94
+ context.User.where(u => u.id.any($$), "1,2,3").toList();
95
+
96
+ // Option 2: .includes() with array (Recommended)
97
+ const ids = [1, 2, 3];
98
+ context.User.where(u => $$.includes(u.id), ids).toList();
99
+
100
+ // Both produce: SELECT * FROM User WHERE id IN (?, ?, ?)
101
+ ```
102
+
103
+ ### LIKE Queries
104
+
105
+ ```javascript
106
+ // Starts with
107
+ context.User.where(u => u.name.like($$), "John%").toList();
108
+
109
+ // Contains
110
+ context.User.where(u => u.email.like($$), "%@example.com%").toList();
111
+
112
+ // Produces: SELECT * FROM User WHERE name LIKE ?
113
+ ```
114
+
115
+ ### Complex Queries
116
+
117
+ ```javascript
118
+ const activeUsers = context.User
119
+ .where(u => $$.includes(u.role_id), [1, 2, 3])
120
+ .and(u => u.active == true)
121
+ .and(u => u.created_at > $, lastWeek)
122
+ .orderByDescending(u => u.created_at)
123
+ .take(50)
124
+ .toList();
125
+ ```
126
+
127
+ ---
128
+
129
+ ## Why Your LLM Might Be Confused
130
+
131
+ ### ❌ Common Misunderstanding
132
+
133
+ ```javascript
134
+ // ❌ WRONG - Trying to call .any() on the dbset
135
+ context.User.any(...) // Error: .any is not a function
136
+
137
+ // ✅ CORRECT - Use .any() inside the lambda expression
138
+ context.User.where(u => u.id.any($$), "1,2,3")
139
+ ```
140
+
141
+ ### Key Difference
142
+
143
+ - **Dbset methods**: Called on `context.EntityName` (e.g., `.new()`, `.add()`)
144
+ - **Lambda functions**: Used inside the `where()` lambda string (e.g., `.any()`, `.like()`)
145
+
146
+ ---
147
+
148
+ ## Implementation Details
149
+
150
+ ### Dbset Methods
151
+ - **File**: `QueryLanguage/queryMethods.js`
152
+ - **Class**: `queryMethods`
153
+ - **Instance**: Created via `context.dbset(Model)`
154
+ - **Methods**: Prototype methods on `queryMethods` class
155
+
156
+ ### Lambda Functions
157
+ - **File**: `QueryLanguage/queryScript.js`
158
+ - **Parsing**: `describeExpressionPartsFunctions()` (lines 304-388)
159
+ - **Whitelist**: `isFunction()` method (lines 505-513)
160
+ - **Recognized**: `any`, `like`, `include`
161
+
162
+ ---
163
+
164
+ ## Quick Reference
165
+
166
+ | What You Want | Correct Syntax |
167
+ |---------------|----------------|
168
+ | Create entity | `context.User.new()` |
169
+ | Add to context | `context.User.add(entity)` |
170
+ | Find by ID | `context.User.where(u => u.id == $, 1).single()` |
171
+ | Find multiple IDs | `context.User.where(u => $$.includes(u.id), [1,2,3]).toList()` |
172
+ | Search text | `context.User.where(u => u.name.like($$), "John%").toList()` |
173
+ | Complex filter | `context.User.where(u => u.active == true).and(u => u.age > $, 18).toList()` |
174
+
175
+ ---
176
+
177
+ ## Summary
178
+
179
+ ✅ **`.new()` is a dbset method** - Added in latest version
180
+ ✅ **`.any()` is a lambda function** - Already existed
181
+ ✅ **`.includes()` is a lambda function** - Transforms to `.any()`
182
+ ✅ **Both are different types of methods used in different places**
183
+
184
+ If your LLM says `.any()` doesn't exist, clarify that it's looking for a **dbset method** when it should be looking for a **lambda expression function**.