@devrev/meerkat-node 0.0.123 → 0.0.124

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.
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Test Helper Utilities
3
+ *
4
+ * Common utilities for Vitest-based comprehensive tests
5
+ */ "use strict";
6
+ function _export(target, all) {
7
+ for(var name in all)Object.defineProperty(target, name, {
8
+ enumerable: true,
9
+ get: all[name]
10
+ });
11
+ }
12
+ _export(exports, {
13
+ BatchErrorReporter: function() {
14
+ return BatchErrorReporter;
15
+ },
16
+ compareNumbers: function() {
17
+ return compareNumbers;
18
+ },
19
+ compareResults: function() {
20
+ return compareResults;
21
+ },
22
+ createReferenceSQL: function() {
23
+ return createReferenceSQL;
24
+ },
25
+ formatSQL: function() {
26
+ return formatSQL;
27
+ },
28
+ generateTestCases: function() {
29
+ return generateTestCases;
30
+ },
31
+ measureExecutionTime: function() {
32
+ return measureExecutionTime;
33
+ },
34
+ retryWithBackoff: function() {
35
+ return retryWithBackoff;
36
+ },
37
+ validateAgainstReference: function() {
38
+ return validateAgainstReference;
39
+ },
40
+ validatePerformance: function() {
41
+ return validatePerformance;
42
+ }
43
+ });
44
+ const _extends = require("@swc/helpers/_/_extends");
45
+ const _duckdbexec = require("../../../duckdb-exec");
46
+ let BatchErrorReporter = class BatchErrorReporter {
47
+ /**
48
+ * Add an error to the batch
49
+ */ addError(testCase, error, context) {
50
+ this.errors.push({
51
+ testCase,
52
+ error,
53
+ context
54
+ });
55
+ }
56
+ /**
57
+ * Check if there are any errors
58
+ */ hasErrors() {
59
+ return this.errors.length > 0;
60
+ }
61
+ /**
62
+ * Get count of errors
63
+ */ getErrorCount() {
64
+ return this.errors.length;
65
+ }
66
+ /**
67
+ * Get all errors
68
+ */ getErrors() {
69
+ return this.errors;
70
+ }
71
+ /**
72
+ * Throw if there are any errors, with a comprehensive report
73
+ */ throwIfErrors() {
74
+ if (this.errors.length === 0) {
75
+ return;
76
+ }
77
+ const report = this.errors.map((e, idx)=>{
78
+ let msg = `\n${idx + 1}. ❌ ${e.testCase}\n Error: ${e.error.message}`;
79
+ if (e.context) {
80
+ msg += `\n Context: ${JSON.stringify(e.context, null, 2)}`;
81
+ }
82
+ if (e.error.stack) {
83
+ const stackLines = e.error.stack.split('\n').slice(1, 3);
84
+ msg += `\n ${stackLines.join('\n ')}`;
85
+ }
86
+ return msg;
87
+ }).join('\n');
88
+ throw new Error(`\n${'='.repeat(80)}\n` + `${this.errors.length} TEST(S) FAILED:\n` + `${'='.repeat(80)}` + report + `\n${'='.repeat(80)}\n`);
89
+ }
90
+ /**
91
+ * Clear all errors
92
+ */ clear() {
93
+ this.errors = [];
94
+ }
95
+ constructor(){
96
+ this.errors = [];
97
+ }
98
+ };
99
+ function compareNumbers(actual, expected, tolerance = 0.0001) {
100
+ return Math.abs(actual - expected) <= tolerance;
101
+ }
102
+ function compareResults(actual, expected, options = {}) {
103
+ const { numericTolerance = 0.0001, ignoreOrder = false, ignoreFields = [] } = options;
104
+ if (actual.length !== expected.length) {
105
+ return {
106
+ match: false,
107
+ diff: `Row count mismatch: expected ${expected.length}, got ${actual.length}`
108
+ };
109
+ }
110
+ // Sort if ignoring order
111
+ const actualSorted = ignoreOrder ? [
112
+ ...actual
113
+ ].sort() : actual;
114
+ const expectedSorted = ignoreOrder ? [
115
+ ...expected
116
+ ].sort() : expected;
117
+ for(let i = 0; i < actualSorted.length; i++){
118
+ const actualRow = actualSorted[i];
119
+ const expectedRow = expectedSorted[i];
120
+ for(const key in expectedRow){
121
+ if (ignoreFields.includes(key)) continue;
122
+ const actualVal = actualRow[key];
123
+ const expectedVal = expectedRow[key];
124
+ // Handle null/undefined
125
+ if (actualVal === null && expectedVal === null) continue;
126
+ if (actualVal === undefined && expectedVal === undefined) continue;
127
+ if (actualVal === null && expectedVal === undefined) continue;
128
+ if (actualVal === undefined && expectedVal === null) continue;
129
+ // Handle numeric comparison with tolerance
130
+ if (typeof expectedVal === 'number' && typeof actualVal === 'number') {
131
+ if (!compareNumbers(actualVal, expectedVal, numericTolerance)) {
132
+ return {
133
+ match: false,
134
+ diff: `Row ${i}, field '${key}': expected ${expectedVal}, got ${actualVal} (diff: ${Math.abs(actualVal - expectedVal)})`
135
+ };
136
+ }
137
+ } else if (actualVal !== expectedVal) {
138
+ return {
139
+ match: false,
140
+ diff: `Row ${i}, field '${key}': expected ${JSON.stringify(expectedVal)}, got ${JSON.stringify(actualVal)}`
141
+ };
142
+ }
143
+ }
144
+ }
145
+ return {
146
+ match: true
147
+ };
148
+ }
149
+ function createReferenceSQL(options) {
150
+ const { select, from, where, groupBy, orderBy, limit } = options;
151
+ let sql = `SELECT ${select.join(', ')} FROM ${from}`;
152
+ if (where) {
153
+ sql += ` WHERE ${where}`;
154
+ }
155
+ if (groupBy && groupBy.length > 0) {
156
+ sql += ` GROUP BY ${groupBy.join(', ')}`;
157
+ }
158
+ if (orderBy && orderBy.length > 0) {
159
+ sql += ` ORDER BY ${orderBy.join(', ')}`;
160
+ }
161
+ if (limit) {
162
+ sql += ` LIMIT ${limit}`;
163
+ }
164
+ return sql;
165
+ }
166
+ async function measureExecutionTime(fn) {
167
+ const startTime = Date.now();
168
+ const result = await fn();
169
+ const duration = Date.now() - startTime;
170
+ return {
171
+ result,
172
+ duration
173
+ };
174
+ }
175
+ function validatePerformance(duration, budgetMs, queryDescription) {
176
+ if (duration > budgetMs) {
177
+ throw new Error(`Performance budget exceeded for "${queryDescription}": ` + `expected < ${budgetMs}ms, got ${duration}ms`);
178
+ }
179
+ }
180
+ async function validateAgainstReference(meerkatResult, referenceSQL, options) {
181
+ const referenceResult = await (0, _duckdbexec.duckdbExec)(referenceSQL);
182
+ const comparison = compareResults(meerkatResult, referenceResult, options);
183
+ if (!comparison.match) {
184
+ throw new Error(`Result mismatch with reference SQL:\n` + ` Reference SQL: ${referenceSQL}\n` + ` Difference: ${comparison.diff}\n` + ` Meerkat rows: ${meerkatResult.length}\n` + ` Reference rows: ${referenceResult.length}`);
185
+ }
186
+ }
187
+ function generateTestCases(template, variations) {
188
+ return variations.map((variation)=>_extends._({}, template, variation));
189
+ }
190
+ function formatSQL(sql, maxLength = 200) {
191
+ if (sql.length <= maxLength) {
192
+ return sql;
193
+ }
194
+ return sql.substring(0, maxLength) + '...';
195
+ }
196
+ async function retryWithBackoff(fn, options = {}) {
197
+ const { maxRetries = 3, initialDelay = 100, maxDelay = 5000, backoffMultiplier = 2 } = options;
198
+ let lastError;
199
+ let delay = initialDelay;
200
+ for(let attempt = 0; attempt <= maxRetries; attempt++){
201
+ try {
202
+ return await fn();
203
+ } catch (error) {
204
+ lastError = error;
205
+ if (attempt < maxRetries) {
206
+ await new Promise((resolve)=>setTimeout(resolve, delay));
207
+ delay = Math.min(delay * backoffMultiplier, maxDelay);
208
+ }
209
+ }
210
+ }
211
+ throw lastError;
212
+ }
213
+
214
+ //# sourceMappingURL=test-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../meerkat-node/src/__tests__/comprehensive/helpers/test-helpers.ts"],"sourcesContent":["/**\n * Test Helper Utilities\n *\n * Common utilities for Vitest-based comprehensive tests\n */\n\nimport { duckdbExec } from '../../../duckdb-exec';\n\n/**\n * Batch Error Reporter\n *\n * Collects multiple test failures and reports them together\n * instead of failing on the first error. Useful for data-driven tests.\n */\nexport class BatchErrorReporter {\n private errors: Array<{ testCase: string; error: Error; context?: any }> = [];\n\n /**\n * Add an error to the batch\n */\n addError(testCase: string, error: Error, context?: any): void {\n this.errors.push({ testCase, error, context });\n }\n\n /**\n * Check if there are any errors\n */\n hasErrors(): boolean {\n return this.errors.length > 0;\n }\n\n /**\n * Get count of errors\n */\n getErrorCount(): number {\n return this.errors.length;\n }\n\n /**\n * Get all errors\n */\n getErrors() {\n return this.errors;\n }\n\n /**\n * Throw if there are any errors, with a comprehensive report\n */\n throwIfErrors(): void {\n if (this.errors.length === 0) {\n return;\n }\n\n const report = this.errors\n .map((e, idx) => {\n let msg = `\\n${idx + 1}. ❌ ${e.testCase}\\n Error: ${\n e.error.message\n }`;\n if (e.context) {\n msg += `\\n Context: ${JSON.stringify(e.context, null, 2)}`;\n }\n if (e.error.stack) {\n const stackLines = e.error.stack.split('\\n').slice(1, 3);\n msg += `\\n ${stackLines.join('\\n ')}`;\n }\n return msg;\n })\n .join('\\n');\n\n throw new Error(\n `\\n${'='.repeat(80)}\\n` +\n `${this.errors.length} TEST(S) FAILED:\\n` +\n `${'='.repeat(80)}` +\n report +\n `\\n${'='.repeat(80)}\\n`\n );\n }\n\n /**\n * Clear all errors\n */\n clear(): void {\n this.errors = [];\n }\n}\n\n/**\n * Compare numeric values with tolerance for floating-point precision\n */\nexport function compareNumbers(\n actual: number,\n expected: number,\n tolerance = 0.0001\n): boolean {\n return Math.abs(actual - expected) <= tolerance;\n}\n\n/**\n * Compare query results with tolerance for numeric fields\n */\nexport function compareResults(\n actual: any[],\n expected: any[],\n options: {\n numericTolerance?: number;\n ignoreOrder?: boolean;\n ignoreFields?: string[];\n } = {}\n): { match: boolean; diff?: string } {\n const {\n numericTolerance = 0.0001,\n ignoreOrder = false,\n ignoreFields = [],\n } = options;\n\n if (actual.length !== expected.length) {\n return {\n match: false,\n diff: `Row count mismatch: expected ${expected.length}, got ${actual.length}`,\n };\n }\n\n // Sort if ignoring order\n const actualSorted = ignoreOrder ? [...actual].sort() : actual;\n const expectedSorted = ignoreOrder ? [...expected].sort() : expected;\n\n for (let i = 0; i < actualSorted.length; i++) {\n const actualRow = actualSorted[i];\n const expectedRow = expectedSorted[i];\n\n for (const key in expectedRow) {\n if (ignoreFields.includes(key)) continue;\n\n const actualVal = actualRow[key];\n const expectedVal = expectedRow[key];\n\n // Handle null/undefined\n if (actualVal === null && expectedVal === null) continue;\n if (actualVal === undefined && expectedVal === undefined) continue;\n if (actualVal === null && expectedVal === undefined) continue;\n if (actualVal === undefined && expectedVal === null) continue;\n\n // Handle numeric comparison with tolerance\n if (typeof expectedVal === 'number' && typeof actualVal === 'number') {\n if (!compareNumbers(actualVal, expectedVal, numericTolerance)) {\n return {\n match: false,\n diff: `Row ${i}, field '${key}': expected ${expectedVal}, got ${actualVal} (diff: ${Math.abs(\n actualVal - expectedVal\n )})`,\n };\n }\n } else if (actualVal !== expectedVal) {\n return {\n match: false,\n diff: `Row ${i}, field '${key}': expected ${JSON.stringify(\n expectedVal\n )}, got ${JSON.stringify(actualVal)}`,\n };\n }\n }\n }\n\n return { match: true };\n}\n\n/**\n * Create a reference SQL query for validation\n * This is the \"oracle\" pattern - we create direct SQL to validate Meerkat's output\n */\nexport function createReferenceSQL(options: {\n select: string[];\n from: string;\n where?: string;\n groupBy?: string[];\n orderBy?: string[];\n limit?: number;\n}): string {\n const { select, from, where, groupBy, orderBy, limit } = options;\n\n let sql = `SELECT ${select.join(', ')} FROM ${from}`;\n\n if (where) {\n sql += ` WHERE ${where}`;\n }\n\n if (groupBy && groupBy.length > 0) {\n sql += ` GROUP BY ${groupBy.join(', ')}`;\n }\n\n if (orderBy && orderBy.length > 0) {\n sql += ` ORDER BY ${orderBy.join(', ')}`;\n }\n\n if (limit) {\n sql += ` LIMIT ${limit}`;\n }\n\n return sql;\n}\n\n/**\n * Measure execution time of a function\n */\nexport async function measureExecutionTime<T>(\n fn: () => Promise<T>\n): Promise<{ result: T; duration: number }> {\n const startTime = Date.now();\n const result = await fn();\n const duration = Date.now() - startTime;\n\n return { result, duration };\n}\n\n/**\n * Validate query performance against a budget\n */\nexport function validatePerformance(\n duration: number,\n budgetMs: number,\n queryDescription: string\n): void {\n if (duration > budgetMs) {\n throw new Error(\n `Performance budget exceeded for \"${queryDescription}\": ` +\n `expected < ${budgetMs}ms, got ${duration}ms`\n );\n }\n}\n\n/**\n * Execute a reference SQL and validate against Meerkat result\n */\nexport async function validateAgainstReference(\n meerkatResult: any[],\n referenceSQL: string,\n options?: {\n numericTolerance?: number;\n ignoreOrder?: boolean;\n ignoreFields?: string[];\n }\n): Promise<void> {\n const referenceResult = await duckdbExec<any[]>(referenceSQL);\n const comparison = compareResults(meerkatResult, referenceResult, options);\n\n if (!comparison.match) {\n throw new Error(\n `Result mismatch with reference SQL:\\n` +\n ` Reference SQL: ${referenceSQL}\\n` +\n ` Difference: ${comparison.diff}\\n` +\n ` Meerkat rows: ${meerkatResult.length}\\n` +\n ` Reference rows: ${referenceResult.length}`\n );\n }\n}\n\n/**\n * Generate test cases for a data-driven test\n */\nexport function generateTestCases<T>(\n template: T,\n variations: Array<Partial<T>>\n): T[] {\n return variations.map((variation) => ({ ...template, ...variation }));\n}\n\n/**\n * Format SQL for error messages (truncate if too long)\n */\nexport function formatSQL(sql: string, maxLength = 200): string {\n if (sql.length <= maxLength) {\n return sql;\n }\n return sql.substring(0, maxLength) + '...';\n}\n\n/**\n * Retry a function with exponential backoff\n * Useful for flaky operations\n */\nexport async function retryWithBackoff<T>(\n fn: () => Promise<T>,\n options: {\n maxRetries?: number;\n initialDelay?: number;\n maxDelay?: number;\n backoffMultiplier?: number;\n } = {}\n): Promise<T> {\n const {\n maxRetries = 3,\n initialDelay = 100,\n maxDelay = 5000,\n backoffMultiplier = 2,\n } = options;\n\n let lastError: Error | undefined;\n let delay = initialDelay;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error as Error;\n\n if (attempt < maxRetries) {\n await new Promise((resolve) => setTimeout(resolve, delay));\n delay = Math.min(delay * backoffMultiplier, maxDelay);\n }\n }\n }\n\n throw lastError;\n}\n"],"names":["BatchErrorReporter","compareNumbers","compareResults","createReferenceSQL","formatSQL","generateTestCases","measureExecutionTime","retryWithBackoff","validateAgainstReference","validatePerformance","addError","testCase","error","context","errors","push","hasErrors","length","getErrorCount","getErrors","throwIfErrors","report","map","e","idx","msg","message","JSON","stringify","stack","stackLines","split","slice","join","Error","repeat","clear","actual","expected","tolerance","Math","abs","options","numericTolerance","ignoreOrder","ignoreFields","match","diff","actualSorted","sort","expectedSorted","i","actualRow","expectedRow","key","includes","actualVal","expectedVal","undefined","select","from","where","groupBy","orderBy","limit","sql","fn","startTime","Date","now","result","duration","budgetMs","queryDescription","meerkatResult","referenceSQL","referenceResult","duckdbExec","comparison","template","variations","variation","maxLength","substring","maxRetries","initialDelay","maxDelay","backoffMultiplier","lastError","delay","attempt","Promise","resolve","setTimeout","min"],"mappings":"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"}
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Synthetic Schema Setup
3
+ *
4
+ * Creates comprehensive test tables with 1M+ rows covering all data types
5
+ * and patterns used in production Meerkat queries.
6
+ */ "use strict";
7
+ function _export(target, all) {
8
+ for(var name in all)Object.defineProperty(target, name, {
9
+ enumerable: true,
10
+ get: all[name]
11
+ });
12
+ }
13
+ _export(exports, {
14
+ createAllSyntheticTables: function() {
15
+ return createAllSyntheticTables;
16
+ },
17
+ createDimPartTable: function() {
18
+ return createDimPartTable;
19
+ },
20
+ createDimUserTable: function() {
21
+ return createDimUserTable;
22
+ },
23
+ createFactAllTypesTable: function() {
24
+ return createFactAllTypesTable;
25
+ },
26
+ dropSyntheticTables: function() {
27
+ return dropSyntheticTables;
28
+ },
29
+ verifySyntheticTables: function() {
30
+ return verifySyntheticTables;
31
+ }
32
+ });
33
+ const _duckdbexec = require("../../../duckdb-exec");
34
+ async function createFactAllTypesTable() {
35
+ console.log('Creating fact_all_types table with 1M rows...');
36
+ await (0, _duckdbexec.duckdbExec)(`
37
+ CREATE TABLE IF NOT EXISTS fact_all_types AS
38
+ SELECT
39
+ -- Keys/IDs
40
+ i AS id_bigint,
41
+ 'inc_' || (i % 100000) AS incident_id,
42
+ 'user_' || (i % 10000) AS user_id,
43
+ 'part_' || (i % 5000) AS part_id,
44
+
45
+ -- Numeric types: BIGINT
46
+ CAST(i * 10 AS BIGINT) AS metric_bigint,
47
+ CAST((i % 1000) AS BIGINT) AS small_bigint,
48
+
49
+ -- Numeric types: NUMERIC/DECIMAL
50
+ CAST((i % 1000) / 10.0 AS DECIMAL(18,2)) AS metric_numeric,
51
+ CAST((i % 10000) / 100.0 AS DECIMAL(18,4)) AS precise_numeric,
52
+
53
+ -- Numeric types: DOUBLE/FLOAT
54
+ (i % 1000) / 3.0 AS metric_double,
55
+ (i % 1000) * 1.5 AS metric_float,
56
+
57
+ -- Boolean
58
+ (i % 10 = 0) AS is_deleted,
59
+ (i % 3 = 0) AS flag_boolean,
60
+ -- Use a different modulus base to avoid correlation with status buckets.
61
+ ((CAST(i / 3 AS BIGINT)) % 2 = 0) AS is_active,
62
+ CASE WHEN i % 7 = 0 THEN NULL ELSE CAST(i % 10000 AS BIGINT) END AS resolved_by,
63
+
64
+ -- Strings/enums (VARCHAR)
65
+ CASE (i % 5)
66
+ WHEN 0 THEN 'high'
67
+ WHEN 1 THEN 'medium'
68
+ WHEN 2 THEN 'low'
69
+ WHEN 3 THEN 'critical'
70
+ ELSE 'unknown'
71
+ END AS priority,
72
+
73
+ CASE (i % 4)
74
+ WHEN 0 THEN 'open'
75
+ WHEN 1 THEN 'in_progress'
76
+ WHEN 2 THEN 'resolved'
77
+ ELSE 'closed'
78
+ END AS status,
79
+
80
+ CASE (i % 3)
81
+ WHEN 0 THEN 'P0'
82
+ WHEN 1 THEN 'P1'
83
+ ELSE 'P2'
84
+ END AS severity_label,
85
+
86
+ CASE (i % 4)
87
+ WHEN 0 THEN 'production'
88
+ WHEN 1 THEN 'staging'
89
+ WHEN 2 THEN 'development'
90
+ ELSE 'test'
91
+ END AS environment,
92
+
93
+ 'Title ' || i AS title,
94
+ 'Test description for incident ' || i AS description,
95
+
96
+ -- Dates (cast to INTEGER for date arithmetic)
97
+ -- Using % 1460 for ~4 year cycle, % 366 for full year including leap day
98
+ DATE '2020-01-01' + CAST((i % 1460) AS INTEGER) AS record_date,
99
+ DATE '2020-01-01' + CAST((i % 366) AS INTEGER) AS created_date,
100
+ DATE '2020-01-01' + CAST(((i + 30) % 1460) AS INTEGER) AS mitigated_date,
101
+ DATE '2019-01-01' + CAST((i % 730) AS INTEGER) AS partition_record_date,
102
+
103
+ -- Timestamps
104
+ TIMESTAMP '2020-01-01 00:00:00' + INTERVAL (CAST((i % 1460) AS INTEGER)) DAY + INTERVAL (CAST((i % 86400) AS INTEGER)) SECOND AS created_timestamp,
105
+ TIMESTAMP '2020-01-01 00:00:00' + INTERVAL (CAST(((i + 100) % 1460) AS INTEGER)) DAY AS identified_timestamp,
106
+ TIMESTAMP '2020-01-01 00:00:00' + INTERVAL (CAST((i % 366) AS INTEGER)) DAY AS deployment_time,
107
+ TIMESTAMP '2020-01-01 00:00:00' + INTERVAL (CAST((i % 1460) AS INTEGER)) DAY AS partition_record_ts,
108
+
109
+ -- Arrays (VARCHAR[])
110
+ CASE
111
+ WHEN i % 4 = 0 THEN ARRAY['backend', 'urgent']
112
+ WHEN i % 4 = 1 THEN ARRAY['frontend']
113
+ WHEN i % 4 = 2 THEN ARRAY['api', 'backend']
114
+ ELSE ARRAY[]::VARCHAR[]
115
+ END AS tags,
116
+
117
+ CASE
118
+ WHEN i % 3 = 0 THEN ARRAY['user_' || ((i % 1000) + 1), 'user_' || ((i % 1000) + 2)]
119
+ WHEN i % 3 = 1 THEN ARRAY['user_' || (i % 1000)]
120
+ ELSE ARRAY[]::VARCHAR[]
121
+ END AS owned_by_ids,
122
+
123
+ CASE
124
+ WHEN i % 5 = 0 THEN ARRAY['part_' || (i % 500), 'part_' || ((i % 500) + 1), 'part_' || ((i % 500) + 2)]
125
+ WHEN i % 5 = 1 THEN ARRAY['part_' || (i % 500)]
126
+ ELSE ARRAY[]::VARCHAR[]
127
+ END AS part_ids,
128
+
129
+ -- JSON-like VARCHAR (to test JSON extraction)
130
+ '{"severity_id": ' || ((i % 5) + 1) || ', "impact": "' ||
131
+ CASE (i % 3)
132
+ WHEN 0 THEN 'high'
133
+ WHEN 1 THEN 'medium'
134
+ ELSE 'low'
135
+ END ||
136
+ '", "source": "' ||
137
+ CASE (i % 3)
138
+ WHEN 0 THEN 'web'
139
+ WHEN 1 THEN 'mobile'
140
+ ELSE 'api'
141
+ END ||
142
+ '", "reported_by": "' || 'user_' || (i % 100) || '"}' AS metadata_json,
143
+
144
+ '{"stage": "' ||
145
+ CASE (i % 4)
146
+ WHEN 0 THEN 'investigation'
147
+ WHEN 1 THEN 'mitigation'
148
+ WHEN 2 THEN 'resolution'
149
+ ELSE 'closed'
150
+ END || '"}' AS stage_json,
151
+
152
+ '{"customers": [' ||
153
+ '"customer_' || (i % 1000) || '", ' ||
154
+ '"customer_' || ((i % 1000) + 1) || '"' ||
155
+ ']}' AS impact_json,
156
+
157
+ -- Derived-style fields (mirroring real widget expressions)
158
+ (i % 10000) AS mtti_seconds,
159
+ MONTHNAME(DATE '2020-01-01' + CAST((i % 365) AS INTEGER)) AS created_month,
160
+ (i % 5) AS severity_id_int,
161
+
162
+ -- Special values for NULL testing
163
+ CASE WHEN i % 10 = 0 THEN NULL ELSE 'value_' || i END AS nullable_string,
164
+ CASE WHEN i % 15 = 0 THEN NULL ELSE (i % 1000) END AS nullable_int,
165
+ CASE WHEN i % 20 = 0 THEN NULL ELSE DATE '2020-01-01' + CAST((i % 365) AS INTEGER) END AS nullable_date,
166
+
167
+ -- Edge case values
168
+ CASE
169
+ WHEN i % 100 = 0 THEN 'value with "quotes"'
170
+ WHEN i % 100 = 1 THEN 'value with ''apostrophe'''
171
+ WHEN i % 100 = 2 THEN 'value with \\ backslash'
172
+ WHEN i % 100 = 3 THEN ''
173
+ ELSE 'normal_value_' || i
174
+ END AS edge_case_string
175
+
176
+ FROM range(0, 1000000) AS t(i)
177
+ `);
178
+ console.log('✅ Created fact_all_types with 1M rows');
179
+ }
180
+ async function createDimUserTable() {
181
+ console.log('Creating dim_user table...');
182
+ await (0, _duckdbexec.duckdbExec)(`
183
+ CREATE TABLE IF NOT EXISTS dim_user AS
184
+ SELECT
185
+ 'user_' || i AS user_id,
186
+ 'User ' || i AS user_name,
187
+ 'user' || i || '@example.com' AS user_email,
188
+ CASE (i % 3)
189
+ WHEN 0 THEN 'enterprise'
190
+ WHEN 1 THEN 'pro'
191
+ ELSE 'free'
192
+ END AS user_segment,
193
+ CASE (i % 4)
194
+ WHEN 0 THEN 'engineering'
195
+ WHEN 1 THEN 'product'
196
+ WHEN 2 THEN 'support'
197
+ ELSE 'sales'
198
+ END AS user_department,
199
+ DATE '2019-01-01' + CAST((i % 1095) AS INTEGER) AS user_created_date,
200
+ (i % 2 = 0) AS is_active_user
201
+ FROM range(0, 10000) AS t(i)
202
+ `);
203
+ console.log('✅ Created dim_user with 10K rows');
204
+ }
205
+ async function createDimPartTable() {
206
+ console.log('Creating dim_part table...');
207
+ await (0, _duckdbexec.duckdbExec)(`
208
+ CREATE TABLE IF NOT EXISTS dim_part AS
209
+ SELECT
210
+ 'part_' || i AS part_id,
211
+ 'Part ' || i AS part_name,
212
+ CASE (i % 5)
213
+ WHEN 0 THEN 'electronics'
214
+ WHEN 1 THEN 'furniture'
215
+ WHEN 2 THEN 'clothing'
216
+ WHEN 3 THEN 'food'
217
+ ELSE 'other'
218
+ END AS product_category,
219
+ CASE (i % 3)
220
+ WHEN 0 THEN 'premium'
221
+ WHEN 1 THEN 'standard'
222
+ ELSE 'budget'
223
+ END AS product_tier,
224
+ (i % 1000) / 10.0 AS weight,
225
+ (i % 10000) / 100.0 AS price,
226
+ (i % 2 = 0) AS in_stock
227
+ FROM range(0, 5000) AS t(i)
228
+ `);
229
+ console.log('✅ Created dim_part with 5K rows');
230
+ }
231
+ async function createAllSyntheticTables() {
232
+ const startTime = Date.now();
233
+ await createFactAllTypesTable();
234
+ await createDimUserTable();
235
+ await createDimPartTable();
236
+ const duration = ((Date.now() - startTime) / 1000).toFixed(2);
237
+ console.log(`\n✅ All synthetic tables created in ${duration}s`);
238
+ }
239
+ async function dropSyntheticTables() {
240
+ console.log('Dropping synthetic tables...');
241
+ await (0, _duckdbexec.duckdbExec)('DROP TABLE IF EXISTS fact_all_types');
242
+ await (0, _duckdbexec.duckdbExec)('DROP TABLE IF EXISTS dim_user');
243
+ await (0, _duckdbexec.duckdbExec)('DROP TABLE IF EXISTS dim_part');
244
+ console.log('✅ Synthetic tables dropped');
245
+ }
246
+ async function verifySyntheticTables() {
247
+ const factCount = await (0, _duckdbexec.duckdbExec)('SELECT COUNT(*) as count FROM fact_all_types');
248
+ const userCount = await (0, _duckdbexec.duckdbExec)('SELECT COUNT(*) as count FROM dim_user');
249
+ const partCount = await (0, _duckdbexec.duckdbExec)('SELECT COUNT(*) as count FROM dim_part');
250
+ console.log('\n📊 Synthetic Table Verification:');
251
+ console.log(` fact_all_types: ${factCount[0].count} rows`);
252
+ console.log(` dim_user: ${userCount[0].count} rows`);
253
+ console.log(` dim_part: ${partCount[0].count} rows`);
254
+ }
255
+
256
+ //# sourceMappingURL=schema-setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../meerkat-node/src/__tests__/comprehensive/synthetic/schema-setup.ts"],"sourcesContent":["/**\n * Synthetic Schema Setup\n * \n * Creates comprehensive test tables with 1M+ rows covering all data types\n * and patterns used in production Meerkat queries.\n */\n\nimport { duckdbExec } from '../../../duckdb-exec';\n\n/**\n * Create the comprehensive fact_all_types table\n * This table contains ~100 columns covering all normalized DB types\n */\nexport async function createFactAllTypesTable(): Promise<void> {\n console.log('Creating fact_all_types table with 1M rows...');\n \n await duckdbExec(`\n CREATE TABLE IF NOT EXISTS fact_all_types AS\n SELECT\n -- Keys/IDs\n i AS id_bigint,\n 'inc_' || (i % 100000) AS incident_id,\n 'user_' || (i % 10000) AS user_id,\n 'part_' || (i % 5000) AS part_id,\n \n -- Numeric types: BIGINT\n CAST(i * 10 AS BIGINT) AS metric_bigint,\n CAST((i % 1000) AS BIGINT) AS small_bigint,\n \n -- Numeric types: NUMERIC/DECIMAL\n CAST((i % 1000) / 10.0 AS DECIMAL(18,2)) AS metric_numeric,\n CAST((i % 10000) / 100.0 AS DECIMAL(18,4)) AS precise_numeric,\n \n -- Numeric types: DOUBLE/FLOAT\n (i % 1000) / 3.0 AS metric_double,\n (i % 1000) * 1.5 AS metric_float,\n \n -- Boolean\n (i % 10 = 0) AS is_deleted,\n (i % 3 = 0) AS flag_boolean,\n -- Use a different modulus base to avoid correlation with status buckets.\n ((CAST(i / 3 AS BIGINT)) % 2 = 0) AS is_active,\n CASE WHEN i % 7 = 0 THEN NULL ELSE CAST(i % 10000 AS BIGINT) END AS resolved_by,\n \n -- Strings/enums (VARCHAR)\n CASE (i % 5)\n WHEN 0 THEN 'high'\n WHEN 1 THEN 'medium'\n WHEN 2 THEN 'low'\n WHEN 3 THEN 'critical'\n ELSE 'unknown'\n END AS priority,\n \n CASE (i % 4)\n WHEN 0 THEN 'open'\n WHEN 1 THEN 'in_progress'\n WHEN 2 THEN 'resolved'\n ELSE 'closed'\n END AS status,\n \n CASE (i % 3)\n WHEN 0 THEN 'P0'\n WHEN 1 THEN 'P1'\n ELSE 'P2'\n END AS severity_label,\n \n CASE (i % 4)\n WHEN 0 THEN 'production'\n WHEN 1 THEN 'staging'\n WHEN 2 THEN 'development'\n ELSE 'test'\n END AS environment,\n \n 'Title ' || i AS title,\n 'Test description for incident ' || i AS description,\n \n -- Dates (cast to INTEGER for date arithmetic)\n -- Using % 1460 for ~4 year cycle, % 366 for full year including leap day\n DATE '2020-01-01' + CAST((i % 1460) AS INTEGER) AS record_date,\n DATE '2020-01-01' + CAST((i % 366) AS INTEGER) AS created_date,\n DATE '2020-01-01' + CAST(((i + 30) % 1460) AS INTEGER) AS mitigated_date,\n DATE '2019-01-01' + CAST((i % 730) AS INTEGER) AS partition_record_date,\n \n -- Timestamps\n TIMESTAMP '2020-01-01 00:00:00' + INTERVAL (CAST((i % 1460) AS INTEGER)) DAY + INTERVAL (CAST((i % 86400) AS INTEGER)) SECOND AS created_timestamp,\n TIMESTAMP '2020-01-01 00:00:00' + INTERVAL (CAST(((i + 100) % 1460) AS INTEGER)) DAY AS identified_timestamp,\n TIMESTAMP '2020-01-01 00:00:00' + INTERVAL (CAST((i % 366) AS INTEGER)) DAY AS deployment_time,\n TIMESTAMP '2020-01-01 00:00:00' + INTERVAL (CAST((i % 1460) AS INTEGER)) DAY AS partition_record_ts,\n \n -- Arrays (VARCHAR[])\n CASE\n WHEN i % 4 = 0 THEN ARRAY['backend', 'urgent']\n WHEN i % 4 = 1 THEN ARRAY['frontend']\n WHEN i % 4 = 2 THEN ARRAY['api', 'backend']\n ELSE ARRAY[]::VARCHAR[]\n END AS tags,\n \n CASE\n WHEN i % 3 = 0 THEN ARRAY['user_' || ((i % 1000) + 1), 'user_' || ((i % 1000) + 2)]\n WHEN i % 3 = 1 THEN ARRAY['user_' || (i % 1000)]\n ELSE ARRAY[]::VARCHAR[]\n END AS owned_by_ids,\n \n CASE\n WHEN i % 5 = 0 THEN ARRAY['part_' || (i % 500), 'part_' || ((i % 500) + 1), 'part_' || ((i % 500) + 2)]\n WHEN i % 5 = 1 THEN ARRAY['part_' || (i % 500)]\n ELSE ARRAY[]::VARCHAR[]\n END AS part_ids,\n \n -- JSON-like VARCHAR (to test JSON extraction)\n '{\"severity_id\": ' || ((i % 5) + 1) || ', \"impact\": \"' ||\n CASE (i % 3)\n WHEN 0 THEN 'high'\n WHEN 1 THEN 'medium'\n ELSE 'low'\n END ||\n '\", \"source\": \"' ||\n CASE (i % 3)\n WHEN 0 THEN 'web'\n WHEN 1 THEN 'mobile'\n ELSE 'api'\n END ||\n '\", \"reported_by\": \"' || 'user_' || (i % 100) || '\"}' AS metadata_json,\n \n '{\"stage\": \"' || \n CASE (i % 4)\n WHEN 0 THEN 'investigation'\n WHEN 1 THEN 'mitigation'\n WHEN 2 THEN 'resolution'\n ELSE 'closed'\n END || '\"}' AS stage_json,\n \n '{\"customers\": [' || \n '\"customer_' || (i % 1000) || '\", ' ||\n '\"customer_' || ((i % 1000) + 1) || '\"' ||\n ']}' AS impact_json,\n \n -- Derived-style fields (mirroring real widget expressions)\n (i % 10000) AS mtti_seconds,\n MONTHNAME(DATE '2020-01-01' + CAST((i % 365) AS INTEGER)) AS created_month,\n (i % 5) AS severity_id_int,\n \n -- Special values for NULL testing\n CASE WHEN i % 10 = 0 THEN NULL ELSE 'value_' || i END AS nullable_string,\n CASE WHEN i % 15 = 0 THEN NULL ELSE (i % 1000) END AS nullable_int,\n CASE WHEN i % 20 = 0 THEN NULL ELSE DATE '2020-01-01' + CAST((i % 365) AS INTEGER) END AS nullable_date,\n \n -- Edge case values\n CASE\n WHEN i % 100 = 0 THEN 'value with \"quotes\"'\n WHEN i % 100 = 1 THEN 'value with ''apostrophe'''\n WHEN i % 100 = 2 THEN 'value with \\\\ backslash'\n WHEN i % 100 = 3 THEN ''\n ELSE 'normal_value_' || i\n END AS edge_case_string\n \n FROM range(0, 1000000) AS t(i)\n `);\n \n console.log('✅ Created fact_all_types with 1M rows');\n}\n\n/**\n * Create dimension table: dim_user\n */\nexport async function createDimUserTable(): Promise<void> {\n console.log('Creating dim_user table...');\n \n await duckdbExec(`\n CREATE TABLE IF NOT EXISTS dim_user AS\n SELECT\n 'user_' || i AS user_id,\n 'User ' || i AS user_name,\n 'user' || i || '@example.com' AS user_email,\n CASE (i % 3)\n WHEN 0 THEN 'enterprise'\n WHEN 1 THEN 'pro'\n ELSE 'free'\n END AS user_segment,\n CASE (i % 4)\n WHEN 0 THEN 'engineering'\n WHEN 1 THEN 'product'\n WHEN 2 THEN 'support'\n ELSE 'sales'\n END AS user_department,\n DATE '2019-01-01' + CAST((i % 1095) AS INTEGER) AS user_created_date,\n (i % 2 = 0) AS is_active_user\n FROM range(0, 10000) AS t(i)\n `);\n \n console.log('✅ Created dim_user with 10K rows');\n}\n\n/**\n * Create dimension table: dim_part\n */\nexport async function createDimPartTable(): Promise<void> {\n console.log('Creating dim_part table...');\n \n await duckdbExec(`\n CREATE TABLE IF NOT EXISTS dim_part AS\n SELECT\n 'part_' || i AS part_id,\n 'Part ' || i AS part_name,\n CASE (i % 5)\n WHEN 0 THEN 'electronics'\n WHEN 1 THEN 'furniture'\n WHEN 2 THEN 'clothing'\n WHEN 3 THEN 'food'\n ELSE 'other'\n END AS product_category,\n CASE (i % 3)\n WHEN 0 THEN 'premium'\n WHEN 1 THEN 'standard'\n ELSE 'budget'\n END AS product_tier,\n (i % 1000) / 10.0 AS weight,\n (i % 10000) / 100.0 AS price,\n (i % 2 = 0) AS in_stock\n FROM range(0, 5000) AS t(i)\n `);\n \n console.log('✅ Created dim_part with 5K rows');\n}\n\n/**\n * Create all synthetic tables in one go\n */\nexport async function createAllSyntheticTables(): Promise<void> {\n const startTime = Date.now();\n \n await createFactAllTypesTable();\n await createDimUserTable();\n await createDimPartTable();\n \n const duration = ((Date.now() - startTime) / 1000).toFixed(2);\n console.log(`\\n✅ All synthetic tables created in ${duration}s`);\n}\n\n/**\n * Drop all synthetic tables (for cleanup)\n */\nexport async function dropSyntheticTables(): Promise<void> {\n console.log('Dropping synthetic tables...');\n \n await duckdbExec('DROP TABLE IF EXISTS fact_all_types');\n await duckdbExec('DROP TABLE IF EXISTS dim_user');\n await duckdbExec('DROP TABLE IF EXISTS dim_part');\n \n console.log('✅ Synthetic tables dropped');\n}\n\n/**\n * Verify tables exist and have data\n */\nexport async function verifySyntheticTables(): Promise<void> {\n const factCount = (await duckdbExec(\n 'SELECT COUNT(*) as count FROM fact_all_types'\n )) as Array<{ count: number }>;\n const userCount = (await duckdbExec(\n 'SELECT COUNT(*) as count FROM dim_user'\n )) as Array<{ count: number }>;\n const partCount = (await duckdbExec(\n 'SELECT COUNT(*) as count FROM dim_part'\n )) as Array<{ count: number }>;\n \n console.log('\\n📊 Synthetic Table Verification:');\n console.log(` fact_all_types: ${factCount[0].count} rows`);\n console.log(` dim_user: ${userCount[0].count} rows`);\n console.log(` dim_part: ${partCount[0].count} rows`);\n}\n\n"],"names":["createAllSyntheticTables","createDimPartTable","createDimUserTable","createFactAllTypesTable","dropSyntheticTables","verifySyntheticTables","console","log","duckdbExec","startTime","Date","now","duration","toFixed","factCount","userCount","partCount","count"],"mappings":"AAAA;;;;;CAKC;;;;;;;;IA+NqBA,wBAAwB;eAAxBA;;IAhCAC,kBAAkB;eAAlBA;;IA/BAC,kBAAkB;eAAlBA;;IAxJAC,uBAAuB;eAAvBA;;IAqOAC,mBAAmB;eAAnBA;;IAaAC,qBAAqB;eAArBA;;;4BAxPK;AAMpB,eAAeF;IACpBG,QAAQC,GAAG,CAAC;IAEZ,MAAMC,IAAAA,sBAAU,EAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6IlB,CAAC;IAEDF,QAAQC,GAAG,CAAC;AACd;AAKO,eAAeL;IACpBI,QAAQC,GAAG,CAAC;IAEZ,MAAMC,IAAAA,sBAAU,EAAC,CAAC;;;;;;;;;;;;;;;;;;;;EAoBlB,CAAC;IAEDF,QAAQC,GAAG,CAAC;AACd;AAKO,eAAeN;IACpBK,QAAQC,GAAG,CAAC;IAEZ,MAAMC,IAAAA,sBAAU,EAAC,CAAC;;;;;;;;;;;;;;;;;;;;;EAqBlB,CAAC;IAEDF,QAAQC,GAAG,CAAC;AACd;AAKO,eAAeP;IACpB,MAAMS,YAAYC,KAAKC,GAAG;IAE1B,MAAMR;IACN,MAAMD;IACN,MAAMD;IAEN,MAAMW,WAAW,AAAC,CAAA,AAACF,CAAAA,KAAKC,GAAG,KAAKF,SAAQ,IAAK,IAAG,EAAGI,OAAO,CAAC;IAC3DP,QAAQC,GAAG,CAAC,CAAC,oCAAoC,EAAEK,SAAS,CAAC,CAAC;AAChE;AAKO,eAAeR;IACpBE,QAAQC,GAAG,CAAC;IAEZ,MAAMC,IAAAA,sBAAU,EAAC;IACjB,MAAMA,IAAAA,sBAAU,EAAC;IACjB,MAAMA,IAAAA,sBAAU,EAAC;IAEjBF,QAAQC,GAAG,CAAC;AACd;AAKO,eAAeF;IACpB,MAAMS,YAAa,MAAMN,IAAAA,sBAAU,EACjC;IAEF,MAAMO,YAAa,MAAMP,IAAAA,sBAAU,EACjC;IAEF,MAAMQ,YAAa,MAAMR,IAAAA,sBAAU,EACjC;IAGFF,QAAQC,GAAG,CAAC;IACZD,QAAQC,GAAG,CAAC,CAAC,mBAAmB,EAAEO,SAAS,CAAC,EAAE,CAACG,KAAK,CAAC,KAAK,CAAC;IAC3DX,QAAQC,GAAG,CAAC,CAAC,aAAa,EAAEQ,SAAS,CAAC,EAAE,CAACE,KAAK,CAAC,KAAK,CAAC;IACrDX,QAAQC,GAAG,CAAC,CAAC,aAAa,EAAES,SAAS,CAAC,EAAE,CAACC,KAAK,CAAC,KAAK,CAAC;AACvD"}