@hypequery/clickhouse 0.2.1 → 0.2.3
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/dist/cli/bin.js +128 -36
- package/dist/cli/generate-types.js +101 -12
- package/dist/core/connection.d.ts +136 -0
- package/dist/core/connection.d.ts.map +1 -1
- package/dist/core/connection.js +58 -0
- package/dist/core/cross-filter.d.ts +85 -0
- package/dist/core/features/aggregations.d.ts +102 -0
- package/dist/core/features/analytics.d.ts +66 -0
- package/dist/core/features/cross-filtering.d.ts +31 -0
- package/dist/core/features/cross-filtering.d.ts.map +1 -0
- package/dist/core/features/cross-filtering.js +123 -0
- package/dist/core/features/executor.d.ts +19 -0
- package/dist/core/features/filtering.d.ts +95 -0
- package/dist/core/features/filtering.d.ts.map +1 -1
- package/dist/core/features/filtering.js +59 -1
- package/dist/core/features/joins.d.ts +29 -0
- package/dist/core/features/pagination.d.ts +23 -0
- package/dist/core/features/query-modifiers.d.ts +119 -0
- package/dist/core/formatters/sql-formatter.d.ts +9 -0
- package/dist/core/formatters/sql-formatter.d.ts.map +1 -1
- package/dist/core/formatters/sql-formatter.js +24 -5
- package/dist/core/join-relationships.d.ts +50 -0
- package/dist/core/query-builder.d.ts +222 -0
- package/dist/core/query-builder.d.ts.map +1 -1
- package/dist/core/query-builder.js +38 -6
- package/dist/core/tests/index.d.ts +2 -0
- package/dist/core/tests/integration/pagination-test-tbc.d.ts +2 -0
- package/dist/core/tests/integration/pagination-test-tbc.d.ts.map +1 -0
- package/dist/core/tests/integration/pagination-test-tbc.js +189 -0
- package/dist/core/tests/integration/setup.d.ts +40 -0
- package/dist/core/tests/integration/setup.d.ts.map +1 -1
- package/dist/core/tests/integration/setup.js +278 -237
- package/dist/core/tests/integration/test-config.d.ts +15 -0
- package/dist/core/tests/integration/test-config.d.ts.map +1 -0
- package/dist/core/tests/integration/test-config.js +15 -0
- package/dist/core/tests/test-utils.d.ts +30 -0
- package/dist/core/utils/logger.d.ts +37 -0
- package/dist/core/utils/logger.js +2 -2
- package/dist/core/utils/sql-expressions.d.ts +59 -0
- package/dist/core/utils.d.ts +3 -0
- package/dist/core/validators/filter-validator.d.ts +8 -0
- package/dist/core/validators/value-validator.d.ts +6 -0
- package/dist/formatters/index.d.ts +1 -0
- package/dist/index.d.ts +10 -27
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -2
- package/dist/types/base.d.ts +77 -0
- package/dist/types/base.d.ts.map +1 -1
- package/dist/types/clickhouse-types.d.ts +13 -0
- package/dist/types/filters.d.ts +37 -0
- package/dist/types/index.d.ts +3 -0
- package/package.json +15 -8
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
// Skipping tests becuase this feature is not ready
|
|
2
|
+
const SKIP_INTEGRATION_TESTS = true; // process.env.SKIP_INTEGRATION_TESTS === 'true' || process.env.CI === 'true';
|
|
3
|
+
describe('Integration Tests - Pagination', () => {
|
|
4
|
+
// Only run these tests if not skipped
|
|
5
|
+
// Removing until this feature is ready
|
|
6
|
+
// (SKIP_INTEGRATION_TESTS ? describe.skip : describe)('ClickHouse Integration', () => {
|
|
7
|
+
// let db: Awaited<ReturnType<typeof initializeTestConnection>>;
|
|
8
|
+
// beforeAll(async () => {
|
|
9
|
+
// if (!SKIP_INTEGRATION_TESTS) {
|
|
10
|
+
// try {
|
|
11
|
+
// // Start ClickHouse container
|
|
12
|
+
// startClickHouseContainer();
|
|
13
|
+
// // Initialize connection
|
|
14
|
+
// db = await initializeTestConnection();
|
|
15
|
+
// // Set up test database
|
|
16
|
+
// await setupTestDatabase();
|
|
17
|
+
// } catch (error) {
|
|
18
|
+
// console.error('Failed to set up integration tests:', error);
|
|
19
|
+
// throw error;
|
|
20
|
+
// }
|
|
21
|
+
// }
|
|
22
|
+
// }, 60000); // Allow up to 60 seconds for setup
|
|
23
|
+
// afterAll(async () => {
|
|
24
|
+
// if (!SKIP_INTEGRATION_TESTS) {
|
|
25
|
+
// try {
|
|
26
|
+
// // Wait for any pending operations to complete
|
|
27
|
+
// console.log('Starting test cleanup...');
|
|
28
|
+
// await new Promise(resolve => setTimeout(resolve, 1000));
|
|
29
|
+
// // Close any active client connections to prevent lingering queries
|
|
30
|
+
// if (db) {
|
|
31
|
+
// try {
|
|
32
|
+
// const client = ClickHouseConnection.getClient();
|
|
33
|
+
// console.log('Closing ClickHouse client connection...');
|
|
34
|
+
// // Wait for any in-flight queries to complete
|
|
35
|
+
// await new Promise(resolve => setTimeout(resolve, 500));
|
|
36
|
+
// // Ensure we're not running any more queries
|
|
37
|
+
// await client.close().catch(err => {
|
|
38
|
+
// console.error('Error closing ClickHouse client:', err);
|
|
39
|
+
// });
|
|
40
|
+
// console.log('ClickHouse client closed successfully');
|
|
41
|
+
// } catch (closeError) {
|
|
42
|
+
// console.error('Error during client close:', closeError);
|
|
43
|
+
// }
|
|
44
|
+
// }
|
|
45
|
+
// // Then stop the container
|
|
46
|
+
// console.log('Stopping ClickHouse container...');
|
|
47
|
+
// await stopClickHouseContainer();
|
|
48
|
+
// console.log('Cleanup completed');
|
|
49
|
+
// // Make sure all async operations have a chance to complete
|
|
50
|
+
// await new Promise(resolve => setTimeout(resolve, 500));
|
|
51
|
+
// } catch (error) {
|
|
52
|
+
// console.error('Error during test cleanup:', error);
|
|
53
|
+
// }
|
|
54
|
+
// }
|
|
55
|
+
// }, 15000); // Allow up to 15 seconds for teardown
|
|
56
|
+
// test('should paginate results with cursor-based pagination', async () => {
|
|
57
|
+
// // Get first page
|
|
58
|
+
// const firstPage = await db.table('test_table')
|
|
59
|
+
// .orderBy('id', 'ASC')
|
|
60
|
+
// .paginate({
|
|
61
|
+
// pageSize: 2,
|
|
62
|
+
// orderBy: [{ column: 'id', direction: 'ASC' }]
|
|
63
|
+
// });
|
|
64
|
+
// expect(firstPage.data).toHaveLength(2);
|
|
65
|
+
// expect(firstPage.pageInfo.hasNextPage).toBe(true);
|
|
66
|
+
// expect(firstPage.pageInfo.hasPreviousPage).toBe(false);
|
|
67
|
+
// expect(firstPage.pageInfo.startCursor).toBeTruthy();
|
|
68
|
+
// expect(firstPage.pageInfo.endCursor).toBeTruthy();
|
|
69
|
+
// expect(firstPage.data[0].id).toBe(1);
|
|
70
|
+
// expect(firstPage.data[1].id).toBe(2);
|
|
71
|
+
// // Get second page using the cursor
|
|
72
|
+
// const secondPage = await db.table('test_table')
|
|
73
|
+
// .orderBy('id', 'ASC')
|
|
74
|
+
// .paginate({
|
|
75
|
+
// pageSize: 2,
|
|
76
|
+
// after: firstPage.pageInfo.endCursor,
|
|
77
|
+
// orderBy: [{ column: 'id', direction: 'ASC' }]
|
|
78
|
+
// });
|
|
79
|
+
// expect(secondPage.data).toHaveLength(2);
|
|
80
|
+
// expect(secondPage.pageInfo.hasNextPage).toBe(true);
|
|
81
|
+
// expect(secondPage.pageInfo.hasPreviousPage).toBe(true);
|
|
82
|
+
// expect(secondPage.data[0].id).toBe(3);
|
|
83
|
+
// expect(secondPage.data[1].id).toBe(4);
|
|
84
|
+
// // Get third page using the cursor
|
|
85
|
+
// const thirdPage = await db.table('test_table')
|
|
86
|
+
// .orderBy('id', 'ASC')
|
|
87
|
+
// .paginate({
|
|
88
|
+
// pageSize: 2,
|
|
89
|
+
// after: secondPage.pageInfo.endCursor,
|
|
90
|
+
// orderBy: [{ column: 'id', direction: 'ASC' }]
|
|
91
|
+
// });
|
|
92
|
+
// expect(thirdPage.data).toHaveLength(1); // Only one record left
|
|
93
|
+
// expect(thirdPage.pageInfo.hasNextPage).toBe(false);
|
|
94
|
+
// expect(thirdPage.pageInfo.hasPreviousPage).toBe(true);
|
|
95
|
+
// expect(thirdPage.data[0].id).toBe(5);
|
|
96
|
+
// });
|
|
97
|
+
// test('should navigate backwards with cursor-based pagination', async () => {
|
|
98
|
+
// // Get first page
|
|
99
|
+
// const firstPage = await db.table('test_table')
|
|
100
|
+
// .orderBy('id', 'ASC')
|
|
101
|
+
// .paginate({
|
|
102
|
+
// pageSize: 2,
|
|
103
|
+
// orderBy: [{ column: 'id', direction: 'ASC' }]
|
|
104
|
+
// });
|
|
105
|
+
// // Get second page
|
|
106
|
+
// const secondPage = await db.table('test_table')
|
|
107
|
+
// .orderBy('id', 'ASC')
|
|
108
|
+
// .paginate({
|
|
109
|
+
// pageSize: 2,
|
|
110
|
+
// after: firstPage.pageInfo.endCursor,
|
|
111
|
+
// orderBy: [{ column: 'id', direction: 'ASC' }]
|
|
112
|
+
// });
|
|
113
|
+
// // Navigate back to first page
|
|
114
|
+
// const backToFirstPage = await db.table('test_table')
|
|
115
|
+
// .orderBy('id', 'ASC')
|
|
116
|
+
// .paginate({
|
|
117
|
+
// pageSize: 2,
|
|
118
|
+
// before: secondPage.pageInfo.startCursor,
|
|
119
|
+
// orderBy: [{ column: 'id', direction: 'ASC' }]
|
|
120
|
+
// });
|
|
121
|
+
// expect(backToFirstPage.data).toHaveLength(2);
|
|
122
|
+
// expect(backToFirstPage.pageInfo.hasNextPage).toBe(true);
|
|
123
|
+
// expect(backToFirstPage.pageInfo.hasPreviousPage).toBe(false);
|
|
124
|
+
// expect(backToFirstPage.data[0].id).toBe(1);
|
|
125
|
+
// expect(backToFirstPage.data[1].id).toBe(2);
|
|
126
|
+
// });
|
|
127
|
+
// test('should handle empty results', async () => {
|
|
128
|
+
// const result = await db.table('test_table')
|
|
129
|
+
// .where('id', 'gt', 100) // No records with id > 100
|
|
130
|
+
// .paginate({
|
|
131
|
+
// pageSize: 10,
|
|
132
|
+
// orderBy: [{ column: 'id', direction: 'ASC' }]
|
|
133
|
+
// });
|
|
134
|
+
// expect(result.data).toHaveLength(0);
|
|
135
|
+
// expect(result.pageInfo.hasNextPage).toBe(false);
|
|
136
|
+
// expect(result.pageInfo.hasPreviousPage).toBe(false);
|
|
137
|
+
// expect(result.pageInfo.startCursor).toBe('');
|
|
138
|
+
// expect(result.pageInfo.endCursor).toBe('');
|
|
139
|
+
// });
|
|
140
|
+
// test('should handle exactly pageSize results', async () => {
|
|
141
|
+
// const result = await db.table('test_table')
|
|
142
|
+
// .where('id', 'lte', 2) // Only 2 records
|
|
143
|
+
// .paginate({
|
|
144
|
+
// pageSize: 2,
|
|
145
|
+
// orderBy: [{ column: 'id', direction: 'ASC' }]
|
|
146
|
+
// });
|
|
147
|
+
// console.log('CHECK!!!!: ', result.pageInfo)
|
|
148
|
+
// expect(result.data).toHaveLength(2);
|
|
149
|
+
// expect(result.pageInfo.hasNextPage).toBe(false);
|
|
150
|
+
// expect(result.pageInfo.hasPreviousPage).toBe(false);
|
|
151
|
+
// });
|
|
152
|
+
// test('should iterate through all pages', async () => {
|
|
153
|
+
// const allResults: any[] = [];
|
|
154
|
+
// for await (const page of db.table('test_table')
|
|
155
|
+
// .orderBy('id', 'ASC')
|
|
156
|
+
// .iteratePages(2)) {
|
|
157
|
+
// allResults.push(...page.data);
|
|
158
|
+
// }
|
|
159
|
+
// expect(allResults).toHaveLength(TEST_DATA.test_table.length);
|
|
160
|
+
// // Check that all records were retrieved in the correct order
|
|
161
|
+
// for (let i = 0; i < allResults.length; i++) {
|
|
162
|
+
// expect(allResults[i].id).toBe(i + 1);
|
|
163
|
+
// }
|
|
164
|
+
// });
|
|
165
|
+
// test('should paginate with complex ordering', async () => {
|
|
166
|
+
// // First page ordered by price descending
|
|
167
|
+
// const firstPage = await db.table('test_table')
|
|
168
|
+
// .paginate({
|
|
169
|
+
// pageSize: 2,
|
|
170
|
+
// orderBy: [{ column: 'price', direction: 'DESC' }]
|
|
171
|
+
// });
|
|
172
|
+
// expect(firstPage.data).toHaveLength(2);
|
|
173
|
+
// // Verify ordering
|
|
174
|
+
// expect(Number(firstPage.data[0].price)).toBeGreaterThanOrEqual(Number(firstPage.data[1].price));
|
|
175
|
+
// // Get second page
|
|
176
|
+
// const secondPage = await db.table('test_table')
|
|
177
|
+
// .paginate({
|
|
178
|
+
// pageSize: 2,
|
|
179
|
+
// after: firstPage.pageInfo.endCursor,
|
|
180
|
+
// orderBy: [{ column: 'price', direction: 'DESC' }]
|
|
181
|
+
// });
|
|
182
|
+
// expect(secondPage.data).toHaveLength(2);
|
|
183
|
+
// // Verify ordering continues correctly
|
|
184
|
+
// expect(Number(firstPage.data[1].price)).toBeGreaterThanOrEqual(Number(secondPage.data[0].price));
|
|
185
|
+
// expect(Number(secondPage.data[0].price)).toBeGreaterThanOrEqual(Number(secondPage.data[1].price));
|
|
186
|
+
// });
|
|
187
|
+
// });
|
|
188
|
+
});
|
|
189
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export declare const initializeTestConnection: () => Promise<{
|
|
2
|
+
table<TableName extends never>(tableName: TableName): import("../../query-builder").QueryBuilder<{}, {}[TableName], false, {}, {}[TableName]>;
|
|
3
|
+
}>;
|
|
4
|
+
export declare const ensureConnectionInitialized: () => import("@clickhouse/client-web/dist/client").WebClickHouseClient;
|
|
5
|
+
export declare const isDockerAvailable: () => Promise<boolean>;
|
|
6
|
+
export declare const isDockerComposeAvailable: () => Promise<boolean>;
|
|
7
|
+
export declare const isContainerRunning: (containerName: string) => Promise<boolean>;
|
|
8
|
+
export declare const isClickHouseReady: () => Promise<boolean>;
|
|
9
|
+
export declare const startClickHouseContainer: () => Promise<void>;
|
|
10
|
+
export declare const waitForClickHouse: (maxAttempts?: number, retryInterval?: number) => Promise<void>;
|
|
11
|
+
export declare const stopClickHouseContainer: () => Promise<void>;
|
|
12
|
+
export interface TestSchemaType {
|
|
13
|
+
test_table: Array<{
|
|
14
|
+
id: number;
|
|
15
|
+
name: string;
|
|
16
|
+
category: string;
|
|
17
|
+
price: number;
|
|
18
|
+
created_at: string;
|
|
19
|
+
is_active: boolean;
|
|
20
|
+
}>;
|
|
21
|
+
users: Array<{
|
|
22
|
+
id: number;
|
|
23
|
+
user_name: string;
|
|
24
|
+
email: string;
|
|
25
|
+
status: string;
|
|
26
|
+
created_at: string;
|
|
27
|
+
}>;
|
|
28
|
+
orders: Array<{
|
|
29
|
+
id: number;
|
|
30
|
+
user_id: number;
|
|
31
|
+
product_id: number;
|
|
32
|
+
quantity: number;
|
|
33
|
+
total: number;
|
|
34
|
+
status: string;
|
|
35
|
+
created_at: string;
|
|
36
|
+
}>;
|
|
37
|
+
}
|
|
38
|
+
export declare const TEST_DATA: TestSchemaType;
|
|
39
|
+
export declare const setupTestDatabase: () => Promise<void>;
|
|
40
|
+
//# sourceMappingURL=setup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../../src/core/tests/integration/setup.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../../src/core/tests/integration/setup.ts"],"names":[],"mappings":"AA6CA,eAAO,MAAM,wBAAwB;;EAyBpC,CAAC;AAGF,eAAO,MAAM,2BAA2B,wEAevC,CAAC;AAGF,eAAO,MAAM,iBAAiB,QAAa,OAAO,CAAC,OAAO,CAOzD,CAAC;AAGF,eAAO,MAAM,wBAAwB,QAAa,OAAO,CAAC,OAAO,CAahE,CAAC;AAGF,eAAO,MAAM,kBAAkB,GAAU,eAAe,MAAM,KAAG,OAAO,CAAC,OAAO,CAO/E,CAAC;AAGF,eAAO,MAAM,iBAAiB,QAAa,OAAO,CAAC,OAAO,CAQzD,CAAC;AAGF,eAAO,MAAM,wBAAwB,QAAa,OAAO,CAAC,IAAI,CAwC7D,CAAC;AAGF,eAAO,MAAM,iBAAiB,GAC5B,oBAAgB,EAChB,sBAAoB,KACnB,OAAO,CAAC,IAAI,CAad,CAAC;AAGF,eAAO,MAAM,uBAAuB,QAAa,OAAO,CAAC,IAAI,CA0B5D,CAAC;AAGF,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,KAAK,CAAC;QAChB,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,OAAO,CAAC;KACpB,CAAC,CAAC;IACH,KAAK,EAAE,KAAK,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;IACH,MAAM,EAAE,KAAK,CAAC;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACJ;AAGD,eAAO,MAAM,SAAS,EAAE,cAoBvB,CAAC;AAGF,eAAO,MAAM,iBAAiB,QAAa,OAAO,CAAC,IAAI,CAuFtD,CAAC"}
|