masterrecord 0.2.34 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +25 -1
- package/Entity/entityModel.js +6 -0
- package/Entity/entityTrackerModel.js +20 -3
- package/Entity/fieldTransformer.js +266 -0
- package/Migrations/migrationMySQLQuery.js +145 -1
- package/Migrations/migrationPostgresQuery.js +402 -0
- package/Migrations/migrationSQLiteQuery.js +145 -1
- package/Migrations/schema.js +131 -28
- package/QueryLanguage/queryMethods.js +193 -15
- package/QueryLanguage/queryParameters.js +136 -0
- package/QueryLanguage/queryScript.js +14 -5
- package/SQLLiteEngine.js +309 -19
- package/context.js +57 -12
- package/docs/INCLUDES_CLARIFICATION.md +202 -0
- package/docs/METHODS_REFERENCE.md +184 -0
- package/docs/MIGRATIONS_GUIDE.md +699 -0
- package/docs/POSTGRESQL_SETUP.md +415 -0
- package/examples/jsonArrayTransformer.js +215 -0
- package/mySQLEngine.js +249 -17
- package/package.json +6 -6
- package/postgresEngine.js +434 -491
- package/postgresSyncConnect.js +209 -0
- package/readme.md +1121 -265
- package/test/anyCommaStringTest.js +237 -0
- package/test/anyMethodTest.js +176 -0
- package/test/findByIdTest.js +227 -0
- package/test/includesFeatureTest.js +183 -0
- package/test/includesTransformTest.js +110 -0
- package/test/newMethodTest.js +330 -0
- package/test/newMethodUnitTest.js +320 -0
- package/test/parameterizedPlaceholderTest.js +159 -0
- package/test/postgresEngineTest.js +463 -0
- package/test/postgresIntegrationTest.js +381 -0
- package/test/securityTest.js +268 -0
- package/test/singleDollarPlaceholderTest.js +238 -0
- package/test/tablePrefixTest.js +100 -0
- package/test/transformerTest.js +287 -0
- package/test/verifyFindById.js +169 -0
- package/test/verifyNewMethod.js +191 -0
- package/test/whereChainingTest.js +88 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify .findById() Method Implementation
|
|
3
|
+
*
|
|
4
|
+
* Simple verification that the .findById() method exists
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
console.log("╔════════════════════════════════════════════════════════════════╗");
|
|
11
|
+
console.log("║ Verify .findById() Method Implementation ║");
|
|
12
|
+
console.log("╚════════════════════════════════════════════════════════════════╝\n");
|
|
13
|
+
|
|
14
|
+
let passed = 0;
|
|
15
|
+
let failed = 0;
|
|
16
|
+
|
|
17
|
+
// Test 1: Check file exists
|
|
18
|
+
console.log("📝 Test 1: Check queryMethods.js exists");
|
|
19
|
+
console.log("──────────────────────────────────────────────────");
|
|
20
|
+
|
|
21
|
+
const queryMethodsPath = path.join(__dirname, '../QueryLanguage/queryMethods.js');
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
if(fs.existsSync(queryMethodsPath)) {
|
|
25
|
+
console.log(" ✓ queryMethods.js found");
|
|
26
|
+
passed++;
|
|
27
|
+
} else {
|
|
28
|
+
console.log(" ✗ queryMethods.js not found");
|
|
29
|
+
failed++;
|
|
30
|
+
}
|
|
31
|
+
} catch(err) {
|
|
32
|
+
console.log(` ✗ Error: ${err.message}`);
|
|
33
|
+
failed++;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Test 2: Check .findById() method exists
|
|
37
|
+
console.log("\n📝 Test 2: Check .findById() method is implemented");
|
|
38
|
+
console.log("──────────────────────────────────────────────────");
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const content = fs.readFileSync(queryMethodsPath, 'utf8');
|
|
42
|
+
|
|
43
|
+
const hasFindByIdMethod = /findById\s*\(\s*id\s*\)\s*\{/.test(content);
|
|
44
|
+
const hasComment = /Convenience method.*Find record by primary key/i.test(content);
|
|
45
|
+
const hasPrimaryKeyDetection = /Find the primary key field/i.test(content);
|
|
46
|
+
|
|
47
|
+
if(hasFindByIdMethod) {
|
|
48
|
+
console.log(" ✓ findById() method definition found");
|
|
49
|
+
|
|
50
|
+
if(hasComment) {
|
|
51
|
+
console.log(" ✓ Method documentation present");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if(hasPrimaryKeyDetection) {
|
|
55
|
+
console.log(" ✓ Primary key detection code present");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
passed++;
|
|
59
|
+
} else {
|
|
60
|
+
console.log(" ✗ findById() method not found");
|
|
61
|
+
failed++;
|
|
62
|
+
}
|
|
63
|
+
} catch(err) {
|
|
64
|
+
console.log(` ✗ Error: ${err.message}`);
|
|
65
|
+
failed++;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Test 3: Verify method implementation
|
|
69
|
+
console.log("\n📝 Test 3: Verify method implementation details");
|
|
70
|
+
console.log("──────────────────────────────────────────────────");
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const content = fs.readFileSync(queryMethodsPath, 'utf8');
|
|
74
|
+
|
|
75
|
+
const checks = [
|
|
76
|
+
{ name: 'Primary key loop', pattern: /for\s*\(\s*const\s+fieldName\s+in\s+this\.__entity\s*\)/ },
|
|
77
|
+
{ name: 'Primary key check', pattern: /field\.primary\s*===\s*true/ },
|
|
78
|
+
{ name: 'Error for missing PK', pattern: /No primary key defined/ },
|
|
79
|
+
{ name: 'WHERE clause builder', pattern: /whereClause\s*=/ },
|
|
80
|
+
{ name: 'Calls .where()', pattern: /this\.where\(whereClause/ },
|
|
81
|
+
{ name: 'Calls .single()', pattern: /\.single\(\)/ }
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
let allChecksPass = true;
|
|
85
|
+
|
|
86
|
+
checks.forEach(check => {
|
|
87
|
+
if(check.pattern.test(content)) {
|
|
88
|
+
console.log(` ✓ ${check.name}`);
|
|
89
|
+
} else {
|
|
90
|
+
console.log(` ✗ Missing: ${check.name}`);
|
|
91
|
+
allChecksPass = false;
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
if(allChecksPass) {
|
|
96
|
+
passed++;
|
|
97
|
+
} else {
|
|
98
|
+
failed++;
|
|
99
|
+
}
|
|
100
|
+
} catch(err) {
|
|
101
|
+
console.log(` ✗ Error: ${err.message}`);
|
|
102
|
+
failed++;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Test 4: Check method placement
|
|
106
|
+
console.log("\n📝 Test 4: Verify method placement in file");
|
|
107
|
+
console.log("──────────────────────────────────────────────────");
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const content = fs.readFileSync(queryMethodsPath, 'utf8');
|
|
111
|
+
|
|
112
|
+
const findByIdIndex = content.indexOf('findById(id)');
|
|
113
|
+
const singleIndex = content.indexOf('single(){');
|
|
114
|
+
|
|
115
|
+
if(findByIdIndex > 0 && singleIndex > 0 && findByIdIndex < singleIndex) {
|
|
116
|
+
console.log(" ✓ findById() placed before single()");
|
|
117
|
+
console.log(" ✓ Correct location in class structure");
|
|
118
|
+
passed++;
|
|
119
|
+
} else if(findByIdIndex > 0) {
|
|
120
|
+
console.log(" ⚠ findById() exists but not in expected location");
|
|
121
|
+
console.log(` ℹ findById at position ${findByIdIndex}`);
|
|
122
|
+
passed++;
|
|
123
|
+
} else {
|
|
124
|
+
console.log(" ✗ Could not verify method placement");
|
|
125
|
+
failed++;
|
|
126
|
+
}
|
|
127
|
+
} catch(err) {
|
|
128
|
+
console.log(` ✗ Error: ${err.message}`);
|
|
129
|
+
failed++;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Summary
|
|
133
|
+
console.log("\n\n╔════════════════════════════════════════════════════════════════╗");
|
|
134
|
+
console.log("║ Verification Summary ║");
|
|
135
|
+
console.log("╚════════════════════════════════════════════════════════════════╝");
|
|
136
|
+
|
|
137
|
+
const total = passed + failed;
|
|
138
|
+
const successRate = total > 0 ? Math.round((passed/total)*100) : 0;
|
|
139
|
+
|
|
140
|
+
console.log(`\n Total Checks: ${total}`);
|
|
141
|
+
console.log(` ✅ Passed: ${passed}`);
|
|
142
|
+
console.log(` ❌ Failed: ${failed}`);
|
|
143
|
+
console.log(` Success Rate: ${successRate}%\n`);
|
|
144
|
+
|
|
145
|
+
if(failed === 0){
|
|
146
|
+
console.log("🎉 All verification checks passed!");
|
|
147
|
+
console.log("\n✨ .findById() Method Successfully Implemented!");
|
|
148
|
+
console.log("\n📖 Implementation Details:");
|
|
149
|
+
console.log(" File: QueryLanguage/queryMethods.js");
|
|
150
|
+
console.log(" Method: findById(id)");
|
|
151
|
+
console.log(" Purpose: Convenience method for finding by primary key");
|
|
152
|
+
console.log("\n📖 Features:");
|
|
153
|
+
console.log(" ✓ Automatically detects primary key field");
|
|
154
|
+
console.log(" ✓ Works with any primary key name (id, user_id, etc.)");
|
|
155
|
+
console.log(" ✓ Validates entity has a primary key");
|
|
156
|
+
console.log(" ✓ Returns single record or null");
|
|
157
|
+
console.log(" ✓ Generates proper parameterized query");
|
|
158
|
+
console.log("\n📖 Usage Examples:");
|
|
159
|
+
console.log(" const user = context.User.findById(123);");
|
|
160
|
+
console.log(" const lead = qaContext.QaLead.findById(leadId);");
|
|
161
|
+
console.log(" const post = context.Post.findById(postId);");
|
|
162
|
+
console.log("\n📖 Equivalent To:");
|
|
163
|
+
console.log(" const user = context.User.where(u => u.id == $$, 123).single();");
|
|
164
|
+
console.log("\n✅ Now compatible with Mongoose/Sequelize-style syntax!\n");
|
|
165
|
+
process.exit(0);
|
|
166
|
+
} else {
|
|
167
|
+
console.log("⚠️ Some verification checks failed.");
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify .new() Method Implementation
|
|
3
|
+
*
|
|
4
|
+
* Simple verification that the .new() method exists in queryMethods.js
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
console.log("╔════════════════════════════════════════════════════════════════╗");
|
|
11
|
+
console.log("║ Verify .new() Method Implementation ║");
|
|
12
|
+
console.log("╚════════════════════════════════════════════════════════════════╝\n");
|
|
13
|
+
|
|
14
|
+
let passed = 0;
|
|
15
|
+
let failed = 0;
|
|
16
|
+
|
|
17
|
+
// Test 1: Check file exists
|
|
18
|
+
console.log("📝 Test 1: Check queryMethods.js exists");
|
|
19
|
+
console.log("──────────────────────────────────────────────────");
|
|
20
|
+
|
|
21
|
+
const queryMethodsPath = path.join(__dirname, '../QueryLanguage/queryMethods.js');
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
if(fs.existsSync(queryMethodsPath)) {
|
|
25
|
+
console.log(" ✓ queryMethods.js found");
|
|
26
|
+
passed++;
|
|
27
|
+
} else {
|
|
28
|
+
console.log(" ✗ queryMethods.js not found");
|
|
29
|
+
failed++;
|
|
30
|
+
}
|
|
31
|
+
} catch(err) {
|
|
32
|
+
console.log(` ✗ Error: ${err.message}`);
|
|
33
|
+
failed++;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Test 2: Check .new() method exists in file
|
|
37
|
+
console.log("\n📝 Test 2: Check .new() method is implemented");
|
|
38
|
+
console.log("──────────────────────────────────────────────────");
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const content = fs.readFileSync(queryMethodsPath, 'utf8');
|
|
42
|
+
|
|
43
|
+
// Check for method definition
|
|
44
|
+
const hasNewMethod = /new\s*\(\s*\)\s*\{/.test(content);
|
|
45
|
+
const hasComment = /Creates a new empty entity instance/i.test(content);
|
|
46
|
+
const hasTracking = /this\.__context\.__track\(newEntity\)/.test(content);
|
|
47
|
+
const hasPropertySetup = /Object\.defineProperty\(newEntity/.test(content);
|
|
48
|
+
|
|
49
|
+
if(hasNewMethod) {
|
|
50
|
+
console.log(" ✓ new() method definition found");
|
|
51
|
+
|
|
52
|
+
if(hasComment) {
|
|
53
|
+
console.log(" ✓ Method documentation present");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if(hasTracking) {
|
|
57
|
+
console.log(" ✓ Entity tracking code present");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if(hasPropertySetup) {
|
|
61
|
+
console.log(" ✓ Property definition code present");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
passed++;
|
|
65
|
+
} else {
|
|
66
|
+
console.log(" ✗ new() method not found in queryMethods.js");
|
|
67
|
+
failed++;
|
|
68
|
+
}
|
|
69
|
+
} catch(err) {
|
|
70
|
+
console.log(` ✗ Error: ${err.message}`);
|
|
71
|
+
failed++;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Test 3: Verify method structure
|
|
75
|
+
console.log("\n📝 Test 3: Verify method implementation structure");
|
|
76
|
+
console.log("──────────────────────────────────────────────────");
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const content = fs.readFileSync(queryMethodsPath, 'utf8');
|
|
80
|
+
|
|
81
|
+
// Extract the new() method
|
|
82
|
+
const methodMatch = content.match(/new\s*\(\s*\)\s*\{[\s\S]*?^\s{4}\}/m);
|
|
83
|
+
|
|
84
|
+
if(methodMatch) {
|
|
85
|
+
const methodCode = methodMatch[0];
|
|
86
|
+
|
|
87
|
+
const checks = [
|
|
88
|
+
{ name: '__state = "insert"', pattern: /__state\s*:\s*"insert"/ },
|
|
89
|
+
{ name: '__entity reference', pattern: /__entity\s*:\s*this\.__entity/ },
|
|
90
|
+
{ name: '__context reference', pattern: /__context\s*:\s*this\.__context/ },
|
|
91
|
+
{ name: '__dirtyFields array', pattern: /__dirtyFields\s*:\s*\[/ },
|
|
92
|
+
{ name: 'Property loop', pattern: /for\s*\(\s*var\s+fieldName\s+in\s+this\.__entity\s*\)/ },
|
|
93
|
+
{ name: 'Skip navigational', pattern: /isNavigational/ },
|
|
94
|
+
{ name: 'defineProperty', pattern: /Object\.defineProperty/ },
|
|
95
|
+
{ name: 'Track entity', pattern: /this\.__context\.__track/ },
|
|
96
|
+
{ name: 'Return entity', pattern: /return\s+newEntity/ }
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
let allChecksPass = true;
|
|
100
|
+
|
|
101
|
+
checks.forEach(check => {
|
|
102
|
+
if(check.pattern.test(methodCode)) {
|
|
103
|
+
console.log(` ✓ ${check.name}`);
|
|
104
|
+
} else {
|
|
105
|
+
console.log(` ✗ Missing: ${check.name}`);
|
|
106
|
+
allChecksPass = false;
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
if(allChecksPass) {
|
|
111
|
+
passed++;
|
|
112
|
+
} else {
|
|
113
|
+
failed++;
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
console.log(" ✗ Could not extract new() method code");
|
|
117
|
+
failed++;
|
|
118
|
+
}
|
|
119
|
+
} catch(err) {
|
|
120
|
+
console.log(` ✗ Error: ${err.message}`);
|
|
121
|
+
failed++;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Test 4: Check method placement
|
|
125
|
+
console.log("\n📝 Test 4: Verify method placement in file");
|
|
126
|
+
console.log("──────────────────────────────────────────────────");
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const content = fs.readFileSync(queryMethodsPath, 'utf8');
|
|
130
|
+
|
|
131
|
+
// Check that new() comes before add()
|
|
132
|
+
const newIndex = content.indexOf('new()');
|
|
133
|
+
const addIndex = content.indexOf('add(entityValue)');
|
|
134
|
+
|
|
135
|
+
if(newIndex > 0 && addIndex > 0 && newIndex < addIndex) {
|
|
136
|
+
console.log(" ✓ new() method placed before add()");
|
|
137
|
+
console.log(" ✓ Correct location in class structure");
|
|
138
|
+
passed++;
|
|
139
|
+
} else if(newIndex > 0 && addIndex > 0) {
|
|
140
|
+
console.log(" ⚠ new() method exists but not in expected location");
|
|
141
|
+
console.log(` ℹ new() at position ${newIndex}, add() at ${addIndex}`);
|
|
142
|
+
passed++;
|
|
143
|
+
} else {
|
|
144
|
+
console.log(" ✗ Could not verify method placement");
|
|
145
|
+
failed++;
|
|
146
|
+
}
|
|
147
|
+
} catch(err) {
|
|
148
|
+
console.log(` ✗ Error: ${err.message}`);
|
|
149
|
+
failed++;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Summary
|
|
153
|
+
console.log("\n\n╔════════════════════════════════════════════════════════════════╗");
|
|
154
|
+
console.log("║ Verification Summary ║");
|
|
155
|
+
console.log("╚════════════════════════════════════════════════════════════════╝");
|
|
156
|
+
|
|
157
|
+
const total = passed + failed;
|
|
158
|
+
const successRate = total > 0 ? Math.round((passed/total)*100) : 0;
|
|
159
|
+
|
|
160
|
+
console.log(`\n Total Checks: ${total}`);
|
|
161
|
+
console.log(` ✅ Passed: ${passed}`);
|
|
162
|
+
console.log(` ❌ Failed: ${failed}`);
|
|
163
|
+
console.log(` Success Rate: ${successRate}%\n`);
|
|
164
|
+
|
|
165
|
+
if(failed === 0){
|
|
166
|
+
console.log("🎉 All verification checks passed!");
|
|
167
|
+
console.log("\n✨ .new() Method Successfully Implemented!");
|
|
168
|
+
console.log("\n📖 Implementation Details:");
|
|
169
|
+
console.log(" File: QueryLanguage/queryMethods.js");
|
|
170
|
+
console.log(" Method: new()");
|
|
171
|
+
console.log(" Purpose: Create empty entity instances for INSERT operations");
|
|
172
|
+
console.log("\n📖 Features:");
|
|
173
|
+
console.log(" ✓ Creates entity with __state = 'insert'");
|
|
174
|
+
console.log(" ✓ Sets up property getters/setters for all fields");
|
|
175
|
+
console.log(" ✓ Tracks dirty fields automatically");
|
|
176
|
+
console.log(" ✓ Skips navigational properties (relationships)");
|
|
177
|
+
console.log(" ✓ Automatically tracks entity in context");
|
|
178
|
+
console.log("\n📖 Usage Example:");
|
|
179
|
+
console.log(" const job = context.QaIntelligenceJob.new();");
|
|
180
|
+
console.log(" job.annotation_id = 123;");
|
|
181
|
+
console.log(" job.job_type = 'auto_rewrite';");
|
|
182
|
+
console.log(" job.status = 'queued';");
|
|
183
|
+
console.log(" job.created_at = Date.now().toString();");
|
|
184
|
+
console.log(" context.saveChanges(); // INSERT INTO QaIntelligenceJob...");
|
|
185
|
+
console.log("\n✅ Bug Fixed: context.QaIntelligenceJob.new() now works!\n");
|
|
186
|
+
process.exit(0);
|
|
187
|
+
} else {
|
|
188
|
+
console.log("⚠️ Some verification checks failed.");
|
|
189
|
+
console.log(" Review the implementation in queryMethods.js");
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Test for where() chaining functionality
|
|
2
|
+
// This test verifies that multiple .where() calls combine properly with AND
|
|
3
|
+
|
|
4
|
+
var queryScript = require('../QueryLanguage/queryScript');
|
|
5
|
+
|
|
6
|
+
console.log('=== MasterRecord where() Chaining Test ===\n');
|
|
7
|
+
|
|
8
|
+
// Simulate what happens in the query builder
|
|
9
|
+
const qs = new queryScript();
|
|
10
|
+
|
|
11
|
+
// Test Case: Two chained where() calls (like the user's example)
|
|
12
|
+
// let query = this._qaContext.QaTask;
|
|
13
|
+
// query = query.where(t => t.assigned_worker_id == $$, this._currentUser.id);
|
|
14
|
+
// query = query.where(t => t.status == $$, status);
|
|
15
|
+
|
|
16
|
+
console.log('Test: Chaining two where() calls');
|
|
17
|
+
console.log(' First: where(t => t.assigned_worker_id == 123)');
|
|
18
|
+
console.log(' Second: where(t => t.status == "pending")');
|
|
19
|
+
console.log();
|
|
20
|
+
|
|
21
|
+
// First where call
|
|
22
|
+
qs.where('t => t.assigned_worker_id == 123', 'QaTask');
|
|
23
|
+
|
|
24
|
+
console.log('After first where():');
|
|
25
|
+
console.log(' script.where exists:', qs.script.where !== false);
|
|
26
|
+
console.log(' script.where.QaTask exists:', qs.script.where && qs.script.where.QaTask !== undefined);
|
|
27
|
+
if (qs.script.where && qs.script.where.QaTask && qs.script.where.QaTask.query) {
|
|
28
|
+
const exprs1 = qs.script.where.QaTask.query.expressions || [];
|
|
29
|
+
console.log(' Expressions count:', exprs1.length);
|
|
30
|
+
console.log(' Expression 1:', JSON.stringify(exprs1[0]));
|
|
31
|
+
}
|
|
32
|
+
console.log();
|
|
33
|
+
|
|
34
|
+
// Second where call (this should MERGE, not overwrite)
|
|
35
|
+
qs.where('t => t.status == "pending"', 'QaTask');
|
|
36
|
+
|
|
37
|
+
console.log('After second where():');
|
|
38
|
+
console.log(' script.where exists:', qs.script.where !== false);
|
|
39
|
+
console.log(' script.where.QaTask exists:', qs.script.where && qs.script.where.QaTask !== undefined);
|
|
40
|
+
|
|
41
|
+
if (qs.script.where && qs.script.where.QaTask && qs.script.where.QaTask.query) {
|
|
42
|
+
const exprs2 = qs.script.where.QaTask.query.expressions || [];
|
|
43
|
+
console.log(' Expressions count:', exprs2.length);
|
|
44
|
+
console.log(' Expression 1:', JSON.stringify(exprs2[0]));
|
|
45
|
+
console.log(' Expression 2:', JSON.stringify(exprs2[1]));
|
|
46
|
+
console.log();
|
|
47
|
+
|
|
48
|
+
// Verify results
|
|
49
|
+
console.log('=== Test Results ===');
|
|
50
|
+
if (exprs2.length === 2) {
|
|
51
|
+
console.log('✓ PASS: Both where conditions are present');
|
|
52
|
+
console.log(' - First condition: assigned_worker_id == 123');
|
|
53
|
+
console.log(' - Second condition: status == "pending"');
|
|
54
|
+
console.log(' - These should be combined with AND in the SQL');
|
|
55
|
+
} else {
|
|
56
|
+
console.log('✗ FAIL: Expected 2 expressions, got', exprs2.length);
|
|
57
|
+
if (exprs2.length === 1) {
|
|
58
|
+
console.log(' - Only the last where() was applied (bug not fixed)');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
console.log('✗ FAIL: script.where structure is invalid');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log();
|
|
66
|
+
console.log('=== Additional Test: Three where() calls ===');
|
|
67
|
+
|
|
68
|
+
// Test with three chained where calls
|
|
69
|
+
const qs2 = new queryScript();
|
|
70
|
+
qs2.where('t => t.user_id == 1', 'Task');
|
|
71
|
+
qs2.where('t => t.status == "active"', 'Task');
|
|
72
|
+
qs2.where('t => t.priority == "high"', 'Task');
|
|
73
|
+
|
|
74
|
+
if (qs2.script.where && qs2.script.where.Task && qs2.script.where.Task.query) {
|
|
75
|
+
const exprs3 = qs2.script.where.Task.query.expressions || [];
|
|
76
|
+
console.log('Expressions count:', exprs3.length);
|
|
77
|
+
if (exprs3.length === 3) {
|
|
78
|
+
console.log('✓ PASS: All three where conditions are present');
|
|
79
|
+
exprs3.forEach((expr, idx) => {
|
|
80
|
+
console.log(` ${idx + 1}. ${expr.field} ${expr.func} ${expr.arg}`);
|
|
81
|
+
});
|
|
82
|
+
} else {
|
|
83
|
+
console.log('✗ FAIL: Expected 3 expressions, got', exprs3.length);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log();
|
|
88
|
+
console.log('=== Test Complete ===');
|