@querypanel/node-sdk 1.0.25 → 1.0.26
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/README.md +23 -0
- package/dist/cjs/__tests__/ingest.test.d.ts +5 -0
- package/dist/cjs/__tests__/ingest.test.d.ts.map +1 -0
- package/dist/cjs/__tests__/ingest.test.js +95 -0
- package/dist/cjs/__tests__/ingest.test.js.map +1 -0
- package/dist/cjs/adapters/clickhouse.d.ts +48 -0
- package/dist/cjs/adapters/clickhouse.d.ts.map +1 -0
- package/dist/cjs/adapters/clickhouse.js +284 -0
- package/dist/cjs/adapters/clickhouse.js.map +1 -0
- package/dist/cjs/adapters/introspection.spec.d.ts +2 -0
- package/dist/cjs/adapters/introspection.spec.d.ts.map +1 -0
- package/dist/cjs/adapters/introspection.spec.js +192 -0
- package/dist/cjs/adapters/introspection.spec.js.map +1 -0
- package/dist/cjs/adapters/postgres.d.ts +46 -0
- package/dist/cjs/adapters/postgres.d.ts.map +1 -0
- package/dist/cjs/adapters/postgres.js +457 -0
- package/dist/cjs/adapters/postgres.js.map +1 -0
- package/dist/cjs/adapters/postgres.spec.d.ts +2 -0
- package/dist/cjs/adapters/postgres.spec.d.ts.map +1 -0
- package/dist/cjs/adapters/postgres.spec.js +37 -0
- package/dist/cjs/adapters/postgres.spec.js.map +1 -0
- package/dist/cjs/adapters/types.d.ts +38 -0
- package/dist/cjs/adapters/types.d.ts.map +1 -0
- package/dist/cjs/adapters/types.js +3 -0
- package/dist/cjs/adapters/types.js.map +1 -0
- package/dist/cjs/anonymize.spec.d.ts +2 -0
- package/dist/cjs/anonymize.spec.d.ts.map +1 -0
- package/dist/cjs/anonymize.spec.js +78 -0
- package/dist/cjs/anonymize.spec.js.map +1 -0
- package/dist/cjs/clickhouseClient.spec.d.ts +2 -0
- package/dist/cjs/clickhouseClient.spec.d.ts.map +1 -0
- package/dist/cjs/clickhouseClient.spec.js +286 -0
- package/dist/cjs/clickhouseClient.spec.js.map +1 -0
- package/dist/cjs/connectors/__tests__/clickhouse.introspect.test.d.ts +2 -0
- package/dist/cjs/connectors/__tests__/clickhouse.introspect.test.d.ts.map +1 -0
- package/dist/cjs/connectors/__tests__/clickhouse.introspect.test.js +119 -0
- package/dist/cjs/connectors/__tests__/clickhouse.introspect.test.js.map +1 -0
- package/dist/cjs/connectors/base.d.ts +13 -0
- package/dist/cjs/connectors/base.d.ts.map +1 -0
- package/dist/cjs/connectors/base.js +3 -0
- package/dist/cjs/connectors/base.js.map +1 -0
- package/dist/cjs/connectors/clickhouse.d.ts +53 -0
- package/dist/cjs/connectors/clickhouse.d.ts.map +1 -0
- package/dist/cjs/connectors/clickhouse.js +270 -0
- package/dist/cjs/connectors/clickhouse.js.map +1 -0
- package/dist/cjs/index.d.ts +490 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +843 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/index.test.d.ts +2 -0
- package/dist/cjs/index.test.d.ts.map +1 -0
- package/dist/cjs/index.test.js +185 -0
- package/dist/cjs/index.test.js.map +1 -0
- package/dist/cjs/introspectV3.d.ts +45 -0
- package/dist/cjs/introspectV3.d.ts.map +1 -0
- package/dist/cjs/introspectV3.js +99 -0
- package/dist/cjs/introspectV3.js.map +1 -0
- package/dist/cjs/multidb.spec.d.ts +2 -0
- package/dist/cjs/multidb.spec.d.ts.map +1 -0
- package/dist/cjs/multidb.spec.js +76 -0
- package/dist/cjs/multidb.spec.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/schema/types.d.ts +73 -0
- package/dist/cjs/schema/types.d.ts.map +1 -0
- package/dist/cjs/schema/types.js +3 -0
- package/dist/cjs/schema/types.js.map +1 -0
- package/dist/cjs/tenant-isolation.spec.d.ts +2 -0
- package/dist/cjs/tenant-isolation.spec.d.ts.map +1 -0
- package/dist/cjs/tenant-isolation.spec.js +420 -0
- package/dist/cjs/tenant-isolation.spec.js.map +1 -0
- package/dist/cjs/utils/clickhouse.d.ts +9 -0
- package/dist/cjs/utils/clickhouse.d.ts.map +1 -0
- package/dist/cjs/utils/clickhouse.js +99 -0
- package/dist/cjs/utils/clickhouse.js.map +1 -0
- package/dist/esm/adapters/clickhouse.d.ts +48 -0
- package/dist/esm/adapters/clickhouse.d.ts.map +1 -0
- package/dist/esm/adapters/clickhouse.js +280 -0
- package/dist/esm/adapters/clickhouse.js.map +1 -0
- package/dist/esm/adapters/introspection.spec.d.ts +2 -0
- package/dist/esm/adapters/introspection.spec.d.ts.map +1 -0
- package/dist/esm/adapters/introspection.spec.js +190 -0
- package/dist/esm/adapters/introspection.spec.js.map +1 -0
- package/dist/esm/adapters/postgres.d.ts +46 -0
- package/dist/esm/adapters/postgres.d.ts.map +1 -0
- package/dist/esm/adapters/postgres.js +453 -0
- package/dist/esm/adapters/postgres.js.map +1 -0
- package/dist/esm/adapters/postgres.spec.d.ts +2 -0
- package/dist/esm/adapters/postgres.spec.d.ts.map +1 -0
- package/dist/esm/adapters/postgres.spec.js +35 -0
- package/dist/esm/adapters/postgres.spec.js.map +1 -0
- package/dist/esm/adapters/types.d.ts +38 -0
- package/dist/esm/adapters/types.d.ts.map +1 -0
- package/dist/esm/adapters/types.js +2 -0
- package/dist/esm/adapters/types.js.map +1 -0
- package/dist/esm/anonymize.spec.d.ts +2 -0
- package/dist/esm/anonymize.spec.d.ts.map +1 -0
- package/dist/esm/anonymize.spec.js +76 -0
- package/dist/esm/anonymize.spec.js.map +1 -0
- package/dist/esm/clickhouseClient.spec.d.ts +2 -0
- package/dist/esm/clickhouseClient.spec.d.ts.map +1 -0
- package/dist/esm/clickhouseClient.spec.js +281 -0
- package/dist/esm/clickhouseClient.spec.js.map +1 -0
- package/dist/esm/connectors/base.d.ts +14 -0
- package/dist/esm/connectors/base.d.ts.map +1 -0
- package/dist/esm/connectors/base.js +2 -0
- package/dist/esm/connectors/base.js.map +1 -0
- package/dist/esm/connectors/clickhouse.d.ts +35 -0
- package/dist/esm/connectors/clickhouse.d.ts.map +1 -0
- package/dist/esm/connectors/clickhouse.js +281 -0
- package/dist/esm/connectors/clickhouse.js.map +1 -0
- package/dist/esm/index.d.ts +490 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +838 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/index.test.d.ts +2 -0
- package/dist/esm/index.test.d.ts.map +1 -0
- package/dist/esm/index.test.js +183 -0
- package/dist/esm/index.test.js.map +1 -0
- package/dist/esm/introspectV3.d.ts +45 -0
- package/dist/esm/introspectV3.d.ts.map +1 -0
- package/dist/esm/introspectV3.js +96 -0
- package/dist/esm/introspectV3.js.map +1 -0
- package/dist/esm/multidb.spec.d.ts +2 -0
- package/dist/esm/multidb.spec.d.ts.map +1 -0
- package/dist/esm/multidb.spec.js +74 -0
- package/dist/esm/multidb.spec.js.map +1 -0
- package/dist/esm/schema/types.d.ts +73 -0
- package/dist/esm/schema/types.d.ts.map +1 -0
- package/dist/esm/schema/types.js +2 -0
- package/dist/esm/schema/types.js.map +1 -0
- package/dist/esm/tenant-isolation.spec.d.ts +2 -0
- package/dist/esm/tenant-isolation.spec.d.ts.map +1 -0
- package/dist/esm/tenant-isolation.spec.js +418 -0
- package/dist/esm/tenant-isolation.spec.js.map +1 -0
- package/dist/esm/utils/clickhouse.d.ts +9 -0
- package/dist/esm/utils/clickhouse.d.ts.map +1 -0
- package/dist/esm/utils/clickhouse.js +92 -0
- package/dist/esm/utils/clickhouse.js.map +1 -0
- package/package.json +73 -53
- package/dist/index.cjs +0 -1471
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -468
- package/dist/index.d.ts +0 -468
- package/dist/index.js +0 -1443
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { QueryPanelSdkAPI } from "./index.js";
|
|
3
|
+
describe("Tenant Isolation", () => {
|
|
4
|
+
let sdk;
|
|
5
|
+
const mockBaseUrl = "https://api.test.com";
|
|
6
|
+
const mockToken = "test-token";
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
sdk = new QueryPanelSdkAPI(mockBaseUrl, mockToken);
|
|
9
|
+
});
|
|
10
|
+
describe("ClickHouse - ensureTenantIsolation", () => {
|
|
11
|
+
it("should add WHERE clause with tenant filter when missing", () => {
|
|
12
|
+
const metadata = {
|
|
13
|
+
name: "analytics",
|
|
14
|
+
dialect: "clickhouse",
|
|
15
|
+
tenantFieldName: "customer_id",
|
|
16
|
+
tenantFieldType: "String",
|
|
17
|
+
enforceTenantIsolation: true,
|
|
18
|
+
};
|
|
19
|
+
const sql = "SELECT * FROM transactions ORDER BY created_at DESC";
|
|
20
|
+
const params = {};
|
|
21
|
+
const tenantId = "customer-123";
|
|
22
|
+
// Access private method for testing
|
|
23
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
24
|
+
expect(result).toContain("WHERE customer_id = {customer_id:String}");
|
|
25
|
+
expect(result).toContain("ORDER BY created_at DESC");
|
|
26
|
+
expect(params).toHaveProperty("customer_id", "customer-123");
|
|
27
|
+
});
|
|
28
|
+
it("should add AND condition when WHERE clause exists", () => {
|
|
29
|
+
const metadata = {
|
|
30
|
+
name: "analytics",
|
|
31
|
+
dialect: "clickhouse",
|
|
32
|
+
tenantFieldName: "customer_id",
|
|
33
|
+
tenantFieldType: "String",
|
|
34
|
+
enforceTenantIsolation: true,
|
|
35
|
+
};
|
|
36
|
+
const sql = "SELECT * FROM transactions WHERE status = 'active' ORDER BY date";
|
|
37
|
+
const params = {};
|
|
38
|
+
const tenantId = "customer-123";
|
|
39
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
40
|
+
expect(result).toContain("customer_id = {customer_id:String}");
|
|
41
|
+
expect(result).toContain("AND");
|
|
42
|
+
expect(result).toContain("status = 'active'");
|
|
43
|
+
expect(params).toHaveProperty("customer_id", "customer-123");
|
|
44
|
+
});
|
|
45
|
+
it("should insert before GROUP BY when no WHERE clause", () => {
|
|
46
|
+
const metadata = {
|
|
47
|
+
name: "analytics",
|
|
48
|
+
dialect: "clickhouse",
|
|
49
|
+
tenantFieldName: "customer_id",
|
|
50
|
+
tenantFieldType: "UUID",
|
|
51
|
+
enforceTenantIsolation: true,
|
|
52
|
+
};
|
|
53
|
+
const sql = "SELECT product_id, COUNT(*) FROM orders GROUP BY product_id";
|
|
54
|
+
const params = {};
|
|
55
|
+
const tenantId = "customer-123";
|
|
56
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
57
|
+
expect(result).toContain("WHERE customer_id = {customer_id:UUID}");
|
|
58
|
+
expect(result).toMatch(/WHERE customer_id.*GROUP BY product_id/);
|
|
59
|
+
expect(params).toHaveProperty("customer_id", "customer-123");
|
|
60
|
+
});
|
|
61
|
+
it("should insert before LIMIT when no WHERE clause", () => {
|
|
62
|
+
const metadata = {
|
|
63
|
+
name: "analytics",
|
|
64
|
+
dialect: "clickhouse",
|
|
65
|
+
tenantFieldName: "tenant_id",
|
|
66
|
+
tenantFieldType: "Int64",
|
|
67
|
+
enforceTenantIsolation: true,
|
|
68
|
+
};
|
|
69
|
+
const sql = "SELECT * FROM events LIMIT 100";
|
|
70
|
+
const params = {};
|
|
71
|
+
const tenantId = "customer-123";
|
|
72
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
73
|
+
expect(result).toContain("WHERE tenant_id = {tenant_id:Int64}");
|
|
74
|
+
expect(result).toMatch(/WHERE tenant_id.*LIMIT 100/);
|
|
75
|
+
expect(params).toHaveProperty("tenant_id", "customer-123");
|
|
76
|
+
});
|
|
77
|
+
it("should not modify SQL if tenant field already present", () => {
|
|
78
|
+
const metadata = {
|
|
79
|
+
name: "analytics",
|
|
80
|
+
dialect: "clickhouse",
|
|
81
|
+
tenantFieldName: "customer_id",
|
|
82
|
+
tenantFieldType: "String",
|
|
83
|
+
enforceTenantIsolation: true,
|
|
84
|
+
};
|
|
85
|
+
const sql = "SELECT * FROM transactions WHERE customer_id = {customer_id:String} AND status = 'active'";
|
|
86
|
+
const params = {};
|
|
87
|
+
const tenantId = "customer-123";
|
|
88
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
89
|
+
// Should not modify SQL since tenant field is already present
|
|
90
|
+
expect(result).toBe(sql);
|
|
91
|
+
expect(params).toHaveProperty("customer_id", "customer-123");
|
|
92
|
+
});
|
|
93
|
+
it("should recognize {tenant_field} syntax without type", () => {
|
|
94
|
+
const metadata = {
|
|
95
|
+
name: "analytics",
|
|
96
|
+
dialect: "clickhouse",
|
|
97
|
+
tenantFieldName: "customer_id",
|
|
98
|
+
tenantFieldType: "String",
|
|
99
|
+
enforceTenantIsolation: true,
|
|
100
|
+
};
|
|
101
|
+
const sql = "SELECT * FROM transactions WHERE customer_id = {customer_id}";
|
|
102
|
+
const params = {};
|
|
103
|
+
const tenantId = "customer-123";
|
|
104
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
105
|
+
// Should not modify SQL since tenant field is already present (without type)
|
|
106
|
+
expect(result).toBe(sql);
|
|
107
|
+
expect(params).toHaveProperty("customer_id", "customer-123");
|
|
108
|
+
});
|
|
109
|
+
it("should handle when API uses different placeholder name than field name", () => {
|
|
110
|
+
const metadata = {
|
|
111
|
+
name: "analytics",
|
|
112
|
+
dialect: "clickhouse",
|
|
113
|
+
tenantFieldName: "customer_id",
|
|
114
|
+
tenantFieldType: "Int32",
|
|
115
|
+
enforceTenantIsolation: true,
|
|
116
|
+
};
|
|
117
|
+
// API returns SQL with placeholder named "tenantId" but field is "customer_id"
|
|
118
|
+
const sql = "SELECT state FROM fraud_transaction WHERE customer_id = {tenantId:Int32} LIMIT 100";
|
|
119
|
+
const params = { tenantId: 3 }; // API provided this
|
|
120
|
+
const tenantId = "123"; // Actual tenant ID from SDK
|
|
121
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
122
|
+
// Should not modify SQL since customer_id field is already filtered
|
|
123
|
+
expect(result).toBe(sql);
|
|
124
|
+
// Should set the placeholder param to the correct tenant ID
|
|
125
|
+
expect(params).toHaveProperty("tenantId", "123");
|
|
126
|
+
});
|
|
127
|
+
it("should handle various placeholder names (userId, orgId, etc)", () => {
|
|
128
|
+
const testCases = [
|
|
129
|
+
{
|
|
130
|
+
placeholder: "userId",
|
|
131
|
+
sql: "SELECT * FROM data WHERE customer_id = {userId:String}",
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
placeholder: "orgId",
|
|
135
|
+
sql: "SELECT * FROM data WHERE customer_id = {orgId:String}",
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
placeholder: "accountId",
|
|
139
|
+
sql: "SELECT * FROM data WHERE customer_id = {accountId:String}",
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
placeholder: "tenant",
|
|
143
|
+
sql: "SELECT * FROM data WHERE customer_id = {tenant:String}",
|
|
144
|
+
},
|
|
145
|
+
];
|
|
146
|
+
testCases.forEach(({ placeholder, sql }) => {
|
|
147
|
+
const metadata = {
|
|
148
|
+
name: "analytics",
|
|
149
|
+
dialect: "clickhouse",
|
|
150
|
+
tenantFieldName: "customer_id",
|
|
151
|
+
tenantFieldType: "String",
|
|
152
|
+
enforceTenantIsolation: true,
|
|
153
|
+
};
|
|
154
|
+
const params = {};
|
|
155
|
+
const tenantId = "tenant-123";
|
|
156
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
157
|
+
// Should not modify SQL
|
|
158
|
+
expect(result).toBe(sql);
|
|
159
|
+
// Should set the correct placeholder param
|
|
160
|
+
expect(params).toHaveProperty(placeholder, "tenant-123");
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
it("should handle different field types", () => {
|
|
164
|
+
const testCases = [
|
|
165
|
+
{ type: "String", expected: "{org_id:String}" },
|
|
166
|
+
{ type: "UUID", expected: "{org_id:UUID}" },
|
|
167
|
+
{ type: "Int64", expected: "{org_id:Int64}" },
|
|
168
|
+
{ type: "UInt64", expected: "{org_id:UInt64}" },
|
|
169
|
+
];
|
|
170
|
+
testCases.forEach(({ type, expected }) => {
|
|
171
|
+
const metadata = {
|
|
172
|
+
name: "analytics",
|
|
173
|
+
dialect: "clickhouse",
|
|
174
|
+
tenantFieldName: "org_id",
|
|
175
|
+
tenantFieldType: type,
|
|
176
|
+
enforceTenantIsolation: true,
|
|
177
|
+
};
|
|
178
|
+
const sql = "SELECT * FROM data";
|
|
179
|
+
const params = {};
|
|
180
|
+
const tenantId = "org-123";
|
|
181
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
182
|
+
expect(result).toContain(`org_id = ${expected}`);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
it("should default to String type when not specified", () => {
|
|
186
|
+
const metadata = {
|
|
187
|
+
name: "analytics",
|
|
188
|
+
dialect: "clickhouse",
|
|
189
|
+
tenantFieldName: "customer_id",
|
|
190
|
+
// tenantFieldType not specified
|
|
191
|
+
enforceTenantIsolation: true,
|
|
192
|
+
};
|
|
193
|
+
const sql = "SELECT * FROM transactions";
|
|
194
|
+
const params = {};
|
|
195
|
+
const tenantId = "customer-123";
|
|
196
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
197
|
+
expect(result).toContain("{customer_id:String}"); // Default to String
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
describe("Postgres - ensureTenantIsolation", () => {
|
|
201
|
+
it("should add WHERE clause for Postgres", () => {
|
|
202
|
+
const metadata = {
|
|
203
|
+
name: "users",
|
|
204
|
+
dialect: "postgres",
|
|
205
|
+
tenantFieldName: "tenant_id",
|
|
206
|
+
enforceTenantIsolation: true,
|
|
207
|
+
};
|
|
208
|
+
const sql = "SELECT * FROM users ORDER BY created_at DESC";
|
|
209
|
+
const params = {};
|
|
210
|
+
const tenantId = "tenant-123";
|
|
211
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
212
|
+
expect(result).toContain("WHERE tenant_id = 'tenant-123'");
|
|
213
|
+
expect(params).toHaveProperty("tenant_id", "tenant-123");
|
|
214
|
+
});
|
|
215
|
+
it("should not modify if tenant field already in SQL", () => {
|
|
216
|
+
const metadata = {
|
|
217
|
+
name: "users",
|
|
218
|
+
dialect: "postgres",
|
|
219
|
+
tenantFieldName: "tenant_id",
|
|
220
|
+
enforceTenantIsolation: true,
|
|
221
|
+
};
|
|
222
|
+
const sql = "SELECT * FROM users WHERE tenant_id = $1 AND active = true";
|
|
223
|
+
const params = { tenant_id: "tenant-123" };
|
|
224
|
+
const tenantId = "tenant-123";
|
|
225
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
226
|
+
// Should not modify since tenant_id is in SQL
|
|
227
|
+
expect(result).toBe(sql);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
describe("Enforcement Control", () => {
|
|
231
|
+
it("should not modify SQL when enforceTenantIsolation is false", () => {
|
|
232
|
+
const metadata = {
|
|
233
|
+
name: "public_data",
|
|
234
|
+
dialect: "clickhouse",
|
|
235
|
+
tenantFieldName: "customer_id",
|
|
236
|
+
tenantFieldType: "String",
|
|
237
|
+
enforceTenantIsolation: false, // Disabled
|
|
238
|
+
};
|
|
239
|
+
const sql = "SELECT * FROM public_transactions";
|
|
240
|
+
const params = {};
|
|
241
|
+
const tenantId = "customer-123";
|
|
242
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
243
|
+
// SQL should not be modified
|
|
244
|
+
expect(result).toBe(sql);
|
|
245
|
+
});
|
|
246
|
+
it("should not modify SQL when tenantFieldName is not set", () => {
|
|
247
|
+
const metadata = {
|
|
248
|
+
name: "analytics",
|
|
249
|
+
dialect: "clickhouse",
|
|
250
|
+
// No tenantFieldName
|
|
251
|
+
enforceTenantIsolation: true,
|
|
252
|
+
};
|
|
253
|
+
const sql = "SELECT * FROM transactions";
|
|
254
|
+
const params = {};
|
|
255
|
+
const tenantId = "customer-123";
|
|
256
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
257
|
+
// SQL should not be modified
|
|
258
|
+
expect(result).toBe(sql);
|
|
259
|
+
});
|
|
260
|
+
it("should still add param when enforcement is disabled but field is set", () => {
|
|
261
|
+
const metadata = {
|
|
262
|
+
name: "analytics",
|
|
263
|
+
dialect: "clickhouse",
|
|
264
|
+
tenantFieldName: "customer_id",
|
|
265
|
+
tenantFieldType: "String",
|
|
266
|
+
enforceTenantIsolation: false,
|
|
267
|
+
};
|
|
268
|
+
const sql = "SELECT * FROM transactions";
|
|
269
|
+
const params = {};
|
|
270
|
+
const tenantId = "customer-123";
|
|
271
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
272
|
+
// SQL not modified, but param should be added
|
|
273
|
+
expect(result).toBe(sql);
|
|
274
|
+
// Note: params won't be added because enforcement is disabled
|
|
275
|
+
// The ensureTenantIsolation returns early
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
describe("Edge Cases", () => {
|
|
279
|
+
it("should replace null tenant parameter value with actual tenantId", () => {
|
|
280
|
+
const metadata = {
|
|
281
|
+
name: "analytics",
|
|
282
|
+
dialect: "clickhouse",
|
|
283
|
+
tenantFieldName: "customer_id",
|
|
284
|
+
tenantFieldType: "Int64",
|
|
285
|
+
enforceTenantIsolation: true,
|
|
286
|
+
};
|
|
287
|
+
const sql = "SELECT COUNT(*) FROM transactions WHERE customer_id = {customer_id:Int64} AND state = {failed_state:String}";
|
|
288
|
+
const params = {
|
|
289
|
+
customer_id: null, // API returned null value
|
|
290
|
+
failed_state: "DECLINE",
|
|
291
|
+
};
|
|
292
|
+
const tenantId = "123";
|
|
293
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
294
|
+
// SQL should not be modified since customer_id is already in the query
|
|
295
|
+
expect(result).toBe(sql);
|
|
296
|
+
// But the null value should be replaced with actual tenantId
|
|
297
|
+
expect(params).toHaveProperty("customer_id", "123");
|
|
298
|
+
expect(params).toHaveProperty("failed_state", "DECLINE");
|
|
299
|
+
});
|
|
300
|
+
it("should handle SQL with semicolon at end", () => {
|
|
301
|
+
const metadata = {
|
|
302
|
+
name: "analytics",
|
|
303
|
+
dialect: "clickhouse",
|
|
304
|
+
tenantFieldName: "customer_id",
|
|
305
|
+
tenantFieldType: "String",
|
|
306
|
+
enforceTenantIsolation: true,
|
|
307
|
+
};
|
|
308
|
+
const sql = "SELECT * FROM transactions;";
|
|
309
|
+
const params = {};
|
|
310
|
+
const tenantId = "customer-123";
|
|
311
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
312
|
+
expect(result).toContain("WHERE customer_id = {customer_id:String}");
|
|
313
|
+
expect(result).toMatch(/WHERE.*customer_id.*;$/);
|
|
314
|
+
});
|
|
315
|
+
it("should handle multi-line SQL", () => {
|
|
316
|
+
const metadata = {
|
|
317
|
+
name: "analytics",
|
|
318
|
+
dialect: "clickhouse",
|
|
319
|
+
tenantFieldName: "customer_id",
|
|
320
|
+
tenantFieldType: "String",
|
|
321
|
+
enforceTenantIsolation: true,
|
|
322
|
+
};
|
|
323
|
+
const sql = `
|
|
324
|
+
SELECT
|
|
325
|
+
product_id,
|
|
326
|
+
COUNT(*) as count
|
|
327
|
+
FROM orders
|
|
328
|
+
GROUP BY product_id
|
|
329
|
+
ORDER BY count DESC
|
|
330
|
+
`;
|
|
331
|
+
const params = {};
|
|
332
|
+
const tenantId = "customer-123";
|
|
333
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
334
|
+
expect(result).toContain("WHERE customer_id = {customer_id:String}");
|
|
335
|
+
expect(result).toMatch(/WHERE.*GROUP BY/s);
|
|
336
|
+
});
|
|
337
|
+
it("should be case-insensitive for SQL keywords", () => {
|
|
338
|
+
const metadata = {
|
|
339
|
+
name: "analytics",
|
|
340
|
+
dialect: "clickhouse",
|
|
341
|
+
tenantFieldName: "customer_id",
|
|
342
|
+
tenantFieldType: "String",
|
|
343
|
+
enforceTenantIsolation: true,
|
|
344
|
+
};
|
|
345
|
+
const sql = "select * from transactions order by date";
|
|
346
|
+
const params = {};
|
|
347
|
+
const tenantId = "customer-123";
|
|
348
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
349
|
+
expect(result).toContain("customer_id = {customer_id:String}");
|
|
350
|
+
});
|
|
351
|
+
it("should handle HAVING clause", () => {
|
|
352
|
+
const metadata = {
|
|
353
|
+
name: "analytics",
|
|
354
|
+
dialect: "clickhouse",
|
|
355
|
+
tenantFieldName: "customer_id",
|
|
356
|
+
tenantFieldType: "String",
|
|
357
|
+
enforceTenantIsolation: true,
|
|
358
|
+
};
|
|
359
|
+
const sql = "SELECT product_id, COUNT(*) as cnt FROM orders GROUP BY product_id HAVING cnt > 10";
|
|
360
|
+
const params = {};
|
|
361
|
+
const tenantId = "customer-123";
|
|
362
|
+
const result = sdk.ensureTenantIsolation(sql, params, metadata, tenantId);
|
|
363
|
+
expect(result).toContain("WHERE customer_id = {customer_id:String}");
|
|
364
|
+
expect(result).toMatch(/WHERE.*GROUP BY/);
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
describe("attachClickhouse configuration", () => {
|
|
368
|
+
it("should default enforceTenantIsolation to true when tenantFieldName is set", () => {
|
|
369
|
+
const mockFn = async () => ({});
|
|
370
|
+
sdk.attachClickhouse("test", mockFn, {
|
|
371
|
+
tenantFieldName: "customer_id",
|
|
372
|
+
tenantFieldType: "String",
|
|
373
|
+
// enforceTenantIsolation not specified
|
|
374
|
+
});
|
|
375
|
+
const metadata = sdk.databaseMetadata.get("test");
|
|
376
|
+
expect(metadata.enforceTenantIsolation).toBe(true);
|
|
377
|
+
});
|
|
378
|
+
it("should respect explicit enforceTenantIsolation value", () => {
|
|
379
|
+
const mockFn = async () => ({});
|
|
380
|
+
sdk.attachClickhouse("test", mockFn, {
|
|
381
|
+
tenantFieldName: "customer_id",
|
|
382
|
+
tenantFieldType: "String",
|
|
383
|
+
enforceTenantIsolation: false,
|
|
384
|
+
});
|
|
385
|
+
const metadata = sdk.databaseMetadata.get("test");
|
|
386
|
+
expect(metadata.enforceTenantIsolation).toBe(false);
|
|
387
|
+
});
|
|
388
|
+
it("should default tenantFieldType to String", () => {
|
|
389
|
+
const mockFn = async () => ({});
|
|
390
|
+
sdk.attachClickhouse("test", mockFn, {
|
|
391
|
+
tenantFieldName: "customer_id",
|
|
392
|
+
// tenantFieldType not specified
|
|
393
|
+
});
|
|
394
|
+
const metadata = sdk.databaseMetadata.get("test");
|
|
395
|
+
expect(metadata.tenantFieldType).toBe("String");
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
describe("attachPostgres configuration", () => {
|
|
399
|
+
it("should default enforceTenantIsolation to true when tenantFieldName is set", () => {
|
|
400
|
+
const mockFn = async () => ({ rows: [], fields: [] });
|
|
401
|
+
sdk.attachPostgres("test", mockFn, {
|
|
402
|
+
tenantFieldName: "tenant_id",
|
|
403
|
+
// enforceTenantIsolation not specified
|
|
404
|
+
});
|
|
405
|
+
const metadata = sdk.databaseMetadata.get("test");
|
|
406
|
+
expect(metadata.enforceTenantIsolation).toBe(true);
|
|
407
|
+
});
|
|
408
|
+
it("should not set tenantFieldType for Postgres", () => {
|
|
409
|
+
const mockFn = async () => ({ rows: [], fields: [] });
|
|
410
|
+
sdk.attachPostgres("test", mockFn, {
|
|
411
|
+
tenantFieldName: "tenant_id",
|
|
412
|
+
});
|
|
413
|
+
const metadata = sdk.databaseMetadata.get("test");
|
|
414
|
+
expect(metadata.tenantFieldType).toBeUndefined();
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
//# sourceMappingURL=tenant-isolation.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant-isolation.spec.js","sourceRoot":"","sources":["../../src/tenant-isolation.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function isNullableType(type: string): boolean;
|
|
2
|
+
export declare function unwrapTypeModifiers(type: string): string;
|
|
3
|
+
export declare function extractPrecisionScale(type: string): {
|
|
4
|
+
precision?: number;
|
|
5
|
+
scale?: number;
|
|
6
|
+
};
|
|
7
|
+
export declare function extractFixedStringLength(type: string): number | undefined;
|
|
8
|
+
export declare function parseKeyExpression(expression?: string | null): string[];
|
|
9
|
+
//# sourceMappingURL=clickhouse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickhouse.d.ts","sourceRoot":"","sources":["../../../src/utils/clickhouse.ts"],"names":[],"mappings":"AAGA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYxD;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAWA;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOzE;AAED,wBAAgB,kBAAkB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,EAAE,CAiCvE"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const WRAPPER_REGEX = /^(Nullable|LowCardinality|SimpleAggregateFunction)\((.+)\)$/i;
|
|
2
|
+
export function isNullableType(type) {
|
|
3
|
+
return /Nullable\s*\(/i.test(type);
|
|
4
|
+
}
|
|
5
|
+
export function unwrapTypeModifiers(type) {
|
|
6
|
+
let current = type.trim();
|
|
7
|
+
let match = WRAPPER_REGEX.exec(current);
|
|
8
|
+
while (match) {
|
|
9
|
+
const inner = match[2];
|
|
10
|
+
if (!inner) {
|
|
11
|
+
break;
|
|
12
|
+
}
|
|
13
|
+
current = inner.trim();
|
|
14
|
+
match = WRAPPER_REGEX.exec(current);
|
|
15
|
+
}
|
|
16
|
+
return current;
|
|
17
|
+
}
|
|
18
|
+
export function extractPrecisionScale(type) {
|
|
19
|
+
const unwrapped = unwrapTypeModifiers(type);
|
|
20
|
+
const decimalMatch = unwrapped.match(/Decimal(?:\d+)?\((\d+)\s*,\s*(\d+)\)/i);
|
|
21
|
+
if (!decimalMatch)
|
|
22
|
+
return {};
|
|
23
|
+
const precision = decimalMatch[1];
|
|
24
|
+
const scale = decimalMatch[2];
|
|
25
|
+
if (!precision || !scale)
|
|
26
|
+
return {};
|
|
27
|
+
return {
|
|
28
|
+
precision: Number.parseInt(precision, 10),
|
|
29
|
+
scale: Number.parseInt(scale, 10),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function extractFixedStringLength(type) {
|
|
33
|
+
const unwrapped = unwrapTypeModifiers(type);
|
|
34
|
+
const match = unwrapped.match(/^(?:FixedString|StringFixed)\((\d+)\)$/i);
|
|
35
|
+
if (!match)
|
|
36
|
+
return undefined;
|
|
37
|
+
const length = match[1];
|
|
38
|
+
if (!length)
|
|
39
|
+
return undefined;
|
|
40
|
+
return Number.parseInt(length, 10);
|
|
41
|
+
}
|
|
42
|
+
export function parseKeyExpression(expression) {
|
|
43
|
+
if (!expression)
|
|
44
|
+
return [];
|
|
45
|
+
let value = expression.trim();
|
|
46
|
+
if (!value)
|
|
47
|
+
return [];
|
|
48
|
+
if (/^tuple\s*\(/i.test(value) && value.endsWith(")")) {
|
|
49
|
+
value = value.replace(/^tuple\s*\(/i, "").replace(/\)$/, "");
|
|
50
|
+
}
|
|
51
|
+
const columns = [];
|
|
52
|
+
let depth = 0;
|
|
53
|
+
let token = "";
|
|
54
|
+
for (const ch of value) {
|
|
55
|
+
if (ch === "(") {
|
|
56
|
+
depth += 1;
|
|
57
|
+
token += ch;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (ch === ")") {
|
|
61
|
+
depth = Math.max(0, depth - 1);
|
|
62
|
+
token += ch;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (ch === "," && depth === 0) {
|
|
66
|
+
const col = token.trim();
|
|
67
|
+
if (col)
|
|
68
|
+
columns.push(stripWrapper(col));
|
|
69
|
+
token = "";
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
token += ch;
|
|
73
|
+
}
|
|
74
|
+
const last = token.trim();
|
|
75
|
+
if (last)
|
|
76
|
+
columns.push(stripWrapper(last));
|
|
77
|
+
return columns.filter(Boolean);
|
|
78
|
+
}
|
|
79
|
+
function stripWrapper(value) {
|
|
80
|
+
const noQuotes = stripQuotes(value);
|
|
81
|
+
const withoutTicks = noQuotes.replace(/`/g, "").trim();
|
|
82
|
+
const parts = withoutTicks.split(".");
|
|
83
|
+
return parts[parts.length - 1]?.trim() ?? "";
|
|
84
|
+
}
|
|
85
|
+
function stripQuotes(value) {
|
|
86
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
87
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
88
|
+
return value.slice(1, -1);
|
|
89
|
+
}
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=clickhouse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickhouse.js","sourceRoot":"","sources":["../../../src/utils/clickhouse.ts"],"names":[],"mappings":"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"}
|