turbine-orm 0.4.0 → 0.5.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/README.md +51 -2
- package/dist/cjs/cli/config.js +161 -0
- package/dist/cjs/cli/index.js +977 -0
- package/dist/cjs/cli/migrate.js +421 -0
- package/dist/cjs/cli/ui.js +237 -0
- package/dist/cjs/client.js +449 -0
- package/dist/cjs/generate.js +301 -0
- package/dist/cjs/index.js +75 -0
- package/dist/cjs/introspect.js +289 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/pipeline.js +71 -0
- package/dist/cjs/query.js +1558 -0
- package/dist/cjs/schema-builder.js +169 -0
- package/dist/cjs/schema-sql.js +371 -0
- package/dist/cjs/schema.js +137 -0
- package/dist/cjs/serverless.js +199 -0
- package/dist/cli/config.js +1 -1
- package/dist/cli/index.js +16 -8
- package/dist/cli/migrate.d.ts +29 -5
- package/dist/cli/migrate.js +58 -35
- package/dist/cli/ui.js +1 -1
- package/dist/client.d.ts +15 -4
- package/dist/client.js +28 -15
- package/dist/generate.d.ts +1 -1
- package/dist/generate.js +13 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/introspect.d.ts +1 -1
- package/dist/introspect.js +1 -1
- package/dist/pipeline.d.ts +1 -1
- package/dist/pipeline.js +1 -1
- package/dist/query.d.ts +55 -11
- package/dist/query.js +135 -140
- package/dist/schema-builder.d.ts +2 -2
- package/dist/schema-builder.js +2 -2
- package/dist/schema-sql.d.ts +1 -1
- package/dist/schema-sql.js +31 -15
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +1 -1
- package/dist/serverless.d.ts +3 -3
- package/dist/serverless.js +4 -4
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/package.json +17 -11
- package/dist/cli/config.d.ts.map +0 -1
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/migrate.d.ts.map +0 -1
- package/dist/cli/ui.d.ts.map +0 -1
- package/dist/client.d.ts.map +0 -1
- package/dist/generate.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/introspect.d.ts.map +0 -1
- package/dist/pipeline.d.ts.map +0 -1
- package/dist/query.d.ts.map +0 -1
- package/dist/schema-builder.d.ts.map +0 -1
- package/dist/schema-sql.d.ts.map +0 -1
- package/dist/schema.d.ts.map +0 -1
- package/dist/serverless.d.ts.map +0 -1
- package/dist/types.d.ts.map +0 -1
package/dist/client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* turbine
|
|
2
|
+
* @batadata/turbine — TurbineClient
|
|
3
3
|
*
|
|
4
4
|
* The main entry point for the Turbine TypeScript SDK.
|
|
5
5
|
* Manages connection pooling and provides typed table accessors.
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* const user = await db.users.findUnique({ where: { id: 1 } });
|
|
17
17
|
*
|
|
18
18
|
* // With base client (dynamic):
|
|
19
|
-
* import { TurbineClient } from 'turbine
|
|
19
|
+
* import { TurbineClient } from '@batadata/turbine';
|
|
20
20
|
* const db = new TurbineClient({ connectionString: '...' }, schema);
|
|
21
21
|
* const users = db.table<User>('users');
|
|
22
22
|
* ```
|
|
@@ -24,19 +24,20 @@
|
|
|
24
24
|
import pg from 'pg';
|
|
25
25
|
import { QueryInterface } from './query.js';
|
|
26
26
|
import { executePipeline } from './pipeline.js';
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Parse int8 (bigint, OID 20) as JavaScript number instead of string.
|
|
29
|
+
* Safe for values up to Number.MAX_SAFE_INTEGER (9,007,199,254,740,991).
|
|
30
|
+
*
|
|
31
|
+
* NOTE: For values exceeding Number.MAX_SAFE_INTEGER, the parser falls back
|
|
32
|
+
* to returning the raw string to avoid precision loss. The generated TypeScript
|
|
33
|
+
* type maps int8/bigint to `number`, which is correct for the vast majority of
|
|
34
|
+
* use cases (IDs, counts, timestamps). If you store values > 2^53 - 1 in a
|
|
35
|
+
* bigint column, the runtime return type will be `string` for those rows.
|
|
36
|
+
*/
|
|
29
37
|
pg.types.setTypeParser(20, (val) => {
|
|
30
38
|
const n = Number(val);
|
|
31
39
|
return Number.isSafeInteger(n) ? n : val; // fall back to string for huge values
|
|
32
40
|
});
|
|
33
|
-
// Parse numeric (OID 1700) as number when safe, string otherwise
|
|
34
|
-
pg.types.setTypeParser(1700, (val) => {
|
|
35
|
-
const n = Number(val);
|
|
36
|
-
if (val.includes('.') && Number.isFinite(n))
|
|
37
|
-
return n;
|
|
38
|
-
return Number.isSafeInteger(n) ? n : val;
|
|
39
|
-
});
|
|
40
41
|
/** Maps isolation level names to SQL */
|
|
41
42
|
const ISOLATION_LEVELS = {
|
|
42
43
|
ReadUncommitted: 'READ UNCOMMITTED',
|
|
@@ -56,12 +57,14 @@ export class TransactionClient {
|
|
|
56
57
|
client;
|
|
57
58
|
schema;
|
|
58
59
|
middlewares;
|
|
60
|
+
queryOptions;
|
|
59
61
|
tableCache = new Map();
|
|
60
62
|
savepointCounter = 0;
|
|
61
|
-
constructor(client, schema, middlewares) {
|
|
63
|
+
constructor(client, schema, middlewares, queryOptions) {
|
|
62
64
|
this.client = client;
|
|
63
65
|
this.schema = schema;
|
|
64
66
|
this.middlewares = middlewares;
|
|
67
|
+
this.queryOptions = queryOptions;
|
|
65
68
|
// Auto-create typed table accessors for all tables in the schema
|
|
66
69
|
for (const tableName of Object.keys(schema.tables)) {
|
|
67
70
|
const camelName = tableName.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
@@ -83,7 +86,7 @@ export class TransactionClient {
|
|
|
83
86
|
// Create a QueryInterface that uses the transaction client as its "pool"
|
|
84
87
|
// We use a proxy pool that routes queries through the transaction client
|
|
85
88
|
const txPool = this.createTxPool();
|
|
86
|
-
qi = new QueryInterface(txPool, name, this.schema, this.middlewares);
|
|
89
|
+
qi = new QueryInterface(txPool, name, this.schema, this.middlewares, this.queryOptions);
|
|
87
90
|
this.tableCache.set(name, qi);
|
|
88
91
|
}
|
|
89
92
|
return qi;
|
|
@@ -145,9 +148,14 @@ export class TurbineClient {
|
|
|
145
148
|
logging;
|
|
146
149
|
tableCache = new Map();
|
|
147
150
|
middlewares = [];
|
|
151
|
+
queryOptions;
|
|
148
152
|
constructor(config = {}, schema) {
|
|
149
153
|
this.logging = config.logging ?? false;
|
|
150
154
|
this.schema = schema;
|
|
155
|
+
this.queryOptions = {
|
|
156
|
+
defaultLimit: config.defaultLimit,
|
|
157
|
+
warnOnUnlimited: config.warnOnUnlimited,
|
|
158
|
+
};
|
|
151
159
|
const poolConfig = {
|
|
152
160
|
max: config.poolSize ?? 10,
|
|
153
161
|
idleTimeoutMillis: config.idleTimeoutMs ?? 30_000,
|
|
@@ -187,6 +195,11 @@ export class TurbineClient {
|
|
|
187
195
|
/**
|
|
188
196
|
* Register a middleware function that runs before/after every query.
|
|
189
197
|
*
|
|
198
|
+
* Middleware can inspect and log query parameters, modify results after execution,
|
|
199
|
+
* and measure timing. Note: query SQL is generated before middleware runs, so
|
|
200
|
+
* modifying params.args in middleware will NOT affect the executed SQL.
|
|
201
|
+
* To intercept queries before SQL generation, use the raw() method instead.
|
|
202
|
+
*
|
|
190
203
|
* @example
|
|
191
204
|
* ```ts
|
|
192
205
|
* // Query timing middleware
|
|
@@ -225,7 +238,7 @@ export class TurbineClient {
|
|
|
225
238
|
table(name) {
|
|
226
239
|
let qi = this.tableCache.get(name);
|
|
227
240
|
if (!qi) {
|
|
228
|
-
qi = new QueryInterface(this.pool, name, this.schema, this.middlewares);
|
|
241
|
+
qi = new QueryInterface(this.pool, name, this.schema, this.middlewares, this.queryOptions);
|
|
229
242
|
this.tableCache.set(name, qi);
|
|
230
243
|
}
|
|
231
244
|
return qi;
|
|
@@ -338,7 +351,7 @@ export class TurbineClient {
|
|
|
338
351
|
}
|
|
339
352
|
await client.query(beginSQL);
|
|
340
353
|
// Create the transaction client with typed table accessors
|
|
341
|
-
const tx = new TransactionClient(client, this.schema, this.middlewares);
|
|
354
|
+
const tx = new TransactionClient(client, this.schema, this.middlewares, this.queryOptions);
|
|
342
355
|
// Dynamically attach table accessors to tx
|
|
343
356
|
for (const tableName of Object.keys(this.schema.tables)) {
|
|
344
357
|
const camelName = tableName.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
package/dist/generate.d.ts
CHANGED
package/dist/generate.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* turbine
|
|
2
|
+
* @batadata/turbine — Code generator
|
|
3
3
|
*
|
|
4
4
|
* Takes an IntrospectedSchema and emits TypeScript files:
|
|
5
5
|
* - types.ts — Entity interfaces, Create/Update input types
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* Output goes to the specified directory (default: ./generated/turbine/).
|
|
10
10
|
*/
|
|
11
11
|
import { writeFileSync, mkdirSync } from 'node:fs';
|
|
12
|
-
import { join } from 'node:path';
|
|
12
|
+
import { join, resolve, relative } from 'node:path';
|
|
13
13
|
import { snakeToPascal, singularize, } from './schema.js';
|
|
14
14
|
/** Get the TypeScript type name for a table (singularized PascalCase) */
|
|
15
15
|
function entityName(tableName) {
|
|
@@ -24,6 +24,12 @@ function escSQ(value) {
|
|
|
24
24
|
// ---------------------------------------------------------------------------
|
|
25
25
|
export function generate(options) {
|
|
26
26
|
const outDir = options.outDir ?? './generated/turbine';
|
|
27
|
+
// Path traversal protection — ensure output stays within project root
|
|
28
|
+
const resolved = resolve(outDir);
|
|
29
|
+
const rel = relative(process.cwd(), resolved);
|
|
30
|
+
if (rel.startsWith('..') || resolve(rel) !== resolved) {
|
|
31
|
+
throw new Error(`Output directory must be within the project root. Got: ${outDir}`);
|
|
32
|
+
}
|
|
27
33
|
mkdirSync(outDir, { recursive: true });
|
|
28
34
|
const files = [];
|
|
29
35
|
// Generate types.ts
|
|
@@ -46,10 +52,10 @@ export function generate(options) {
|
|
|
46
52
|
function generatedFileHeader() {
|
|
47
53
|
return [
|
|
48
54
|
'/**',
|
|
49
|
-
' * Auto-generated by turbine
|
|
55
|
+
' * Auto-generated by @batadata/turbine — DO NOT EDIT',
|
|
50
56
|
' *',
|
|
51
57
|
` * Generated at: ${new Date().toISOString()}`,
|
|
52
|
-
' * @see https://
|
|
58
|
+
' * @see https://batadata.com/docs/turbine',
|
|
53
59
|
' */',
|
|
54
60
|
'',
|
|
55
61
|
];
|
|
@@ -136,7 +142,7 @@ function generateTypes(schema) {
|
|
|
136
142
|
function generateMetadata(schema) {
|
|
137
143
|
const lines = [
|
|
138
144
|
...generatedFileHeader(),
|
|
139
|
-
"import type { SchemaMetadata } from 'turbine
|
|
145
|
+
"import type { SchemaMetadata } from '@batadata/turbine';",
|
|
140
146
|
'',
|
|
141
147
|
'export const SCHEMA: SchemaMetadata = {',
|
|
142
148
|
' tables: {',
|
|
@@ -209,8 +215,8 @@ function generateIndex(schema) {
|
|
|
209
215
|
const tableEntries = Object.values(schema.tables);
|
|
210
216
|
const lines = [
|
|
211
217
|
...generatedFileHeader(),
|
|
212
|
-
"import { TurbineClient as BaseTurbineClient, QueryInterface } from 'turbine
|
|
213
|
-
"import type { TurbineConfig } from 'turbine
|
|
218
|
+
"import { TurbineClient as BaseTurbineClient, QueryInterface } from '@batadata/turbine';",
|
|
219
|
+
"import type { TurbineConfig } from '@batadata/turbine';",
|
|
214
220
|
"import { SCHEMA } from './metadata.js';",
|
|
215
221
|
];
|
|
216
222
|
// Import all entity types
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/introspect.d.ts
CHANGED
package/dist/introspect.js
CHANGED
package/dist/pipeline.d.ts
CHANGED
package/dist/pipeline.js
CHANGED
package/dist/query.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* turbine
|
|
2
|
+
* @batadata/turbine — Query builder
|
|
3
3
|
*
|
|
4
4
|
* Each table accessor (db.users, db.posts, etc.) returns a QueryInterface<T>
|
|
5
5
|
* that builds parameterized SQL and executes it through the connection pool.
|
|
@@ -35,6 +35,8 @@ export interface WhereOperator<V = unknown> {
|
|
|
35
35
|
contains?: string;
|
|
36
36
|
startsWith?: string;
|
|
37
37
|
endsWith?: string;
|
|
38
|
+
/** Set to 'insensitive' to use ILIKE instead of LIKE for string comparisons */
|
|
39
|
+
mode?: 'default' | 'insensitive';
|
|
38
40
|
}
|
|
39
41
|
/**
|
|
40
42
|
* A where value can be:
|
|
@@ -77,6 +79,8 @@ export interface FindUniqueArgs<T> {
|
|
|
77
79
|
select?: Record<string, boolean>;
|
|
78
80
|
omit?: Record<string, boolean>;
|
|
79
81
|
with?: WithClause;
|
|
82
|
+
/** Query timeout in milliseconds. Rejects with an error if exceeded. */
|
|
83
|
+
timeout?: number;
|
|
80
84
|
}
|
|
81
85
|
export interface FindManyArgs<T> {
|
|
82
86
|
where?: WhereClause<T>;
|
|
@@ -92,36 +96,54 @@ export interface FindManyArgs<T> {
|
|
|
92
96
|
take?: number;
|
|
93
97
|
/** De-duplicate results by specified fields */
|
|
94
98
|
distinct?: (keyof T & string)[];
|
|
99
|
+
/** Query timeout in milliseconds. Rejects with an error if exceeded. */
|
|
100
|
+
timeout?: number;
|
|
95
101
|
}
|
|
96
102
|
export interface CreateArgs<T> {
|
|
97
103
|
data: Partial<T>;
|
|
104
|
+
/** Query timeout in milliseconds. Rejects with an error if exceeded. */
|
|
105
|
+
timeout?: number;
|
|
98
106
|
}
|
|
99
107
|
export interface CreateManyArgs<T> {
|
|
100
108
|
data: Partial<T>[];
|
|
101
109
|
/** When true, adds ON CONFLICT DO NOTHING to skip duplicate rows */
|
|
102
110
|
skipDuplicates?: boolean;
|
|
111
|
+
/** Query timeout in milliseconds. Rejects with an error if exceeded. */
|
|
112
|
+
timeout?: number;
|
|
103
113
|
}
|
|
104
114
|
export interface UpdateArgs<T> {
|
|
105
115
|
where: WhereClause<T>;
|
|
106
116
|
data: Partial<T>;
|
|
117
|
+
/** Query timeout in milliseconds. Rejects with an error if exceeded. */
|
|
118
|
+
timeout?: number;
|
|
107
119
|
}
|
|
108
120
|
export interface UpdateManyArgs<T> {
|
|
109
121
|
where: WhereClause<T>;
|
|
110
122
|
data: Partial<T>;
|
|
123
|
+
/** Query timeout in milliseconds. Rejects with an error if exceeded. */
|
|
124
|
+
timeout?: number;
|
|
111
125
|
}
|
|
112
126
|
export interface DeleteArgs<T> {
|
|
113
127
|
where: WhereClause<T>;
|
|
128
|
+
/** Query timeout in milliseconds. Rejects with an error if exceeded. */
|
|
129
|
+
timeout?: number;
|
|
114
130
|
}
|
|
115
131
|
export interface DeleteManyArgs<T> {
|
|
116
132
|
where: WhereClause<T>;
|
|
133
|
+
/** Query timeout in milliseconds. Rejects with an error if exceeded. */
|
|
134
|
+
timeout?: number;
|
|
117
135
|
}
|
|
118
136
|
export interface UpsertArgs<T> {
|
|
119
137
|
where: WhereClause<T>;
|
|
120
138
|
create: Partial<T>;
|
|
121
139
|
update: Partial<T>;
|
|
140
|
+
/** Query timeout in milliseconds. Rejects with an error if exceeded. */
|
|
141
|
+
timeout?: number;
|
|
122
142
|
}
|
|
123
143
|
export interface CountArgs<T> {
|
|
124
144
|
where?: WhereClause<T>;
|
|
145
|
+
/** Query timeout in milliseconds. Rejects with an error if exceeded. */
|
|
146
|
+
timeout?: number;
|
|
125
147
|
}
|
|
126
148
|
export interface GroupByArgs<T> {
|
|
127
149
|
by: (keyof T & string)[];
|
|
@@ -140,6 +162,8 @@ export interface GroupByArgs<T> {
|
|
|
140
162
|
having?: Record<string, unknown>;
|
|
141
163
|
/** Order groups */
|
|
142
164
|
orderBy?: Record<string, OrderDirection>;
|
|
165
|
+
/** Query timeout in milliseconds. Rejects with an error if exceeded. */
|
|
166
|
+
timeout?: number;
|
|
143
167
|
}
|
|
144
168
|
/** Arguments for the standalone aggregate method */
|
|
145
169
|
export interface AggregateArgs<T> {
|
|
@@ -154,6 +178,8 @@ export interface AggregateArgs<T> {
|
|
|
154
178
|
_min?: Partial<Record<keyof T & string, boolean>>;
|
|
155
179
|
/** Maximum value of fields */
|
|
156
180
|
_max?: Partial<Record<keyof T & string, boolean>>;
|
|
181
|
+
/** Query timeout in milliseconds. Rejects with an error if exceeded. */
|
|
182
|
+
timeout?: number;
|
|
157
183
|
}
|
|
158
184
|
/** Result type for aggregate queries */
|
|
159
185
|
export interface AggregateResult<T> {
|
|
@@ -211,6 +237,13 @@ type MiddlewareFn = (params: {
|
|
|
211
237
|
action: string;
|
|
212
238
|
args: Record<string, unknown>;
|
|
213
239
|
}) => Promise<unknown>) => Promise<unknown>;
|
|
240
|
+
/** Options passed from TurbineClient to QueryInterface */
|
|
241
|
+
export interface QueryInterfaceOptions {
|
|
242
|
+
/** Default LIMIT applied to findMany() when no limit is specified */
|
|
243
|
+
defaultLimit?: number;
|
|
244
|
+
/** Log a warning when findMany() is called without a limit */
|
|
245
|
+
warnOnUnlimited?: boolean;
|
|
246
|
+
}
|
|
214
247
|
export declare class QueryInterface<T extends object> {
|
|
215
248
|
private readonly pool;
|
|
216
249
|
private readonly table;
|
|
@@ -219,11 +252,25 @@ export declare class QueryInterface<T extends object> {
|
|
|
219
252
|
/** SQL template cache: cacheKey → sql string (params are always positional $1,$2,...) */
|
|
220
253
|
private readonly sqlCache;
|
|
221
254
|
private readonly middlewares;
|
|
222
|
-
private readonly
|
|
223
|
-
|
|
255
|
+
private readonly defaultLimit?;
|
|
256
|
+
private readonly warnOnUnlimited;
|
|
257
|
+
/** Pre-computed column type lookups (avoids linear scans per query) */
|
|
258
|
+
private readonly columnPgTypeMap;
|
|
259
|
+
private readonly columnArrayTypeMap;
|
|
260
|
+
constructor(pool: pg.Pool, table: string, schema: SchemaMetadata, middlewares?: MiddlewareFn[], options?: QueryInterfaceOptions);
|
|
261
|
+
/**
|
|
262
|
+
* Execute a pool.query with an optional timeout.
|
|
263
|
+
* If timeout is set, races the query against a timer and rejects on expiry.
|
|
264
|
+
*/
|
|
265
|
+
private queryWithTimeout;
|
|
224
266
|
/**
|
|
225
267
|
* Execute a query through the middleware chain.
|
|
226
268
|
* If no middlewares are registered, executes directly.
|
|
269
|
+
*
|
|
270
|
+
* Middleware can inspect and log query parameters, modify results after execution,
|
|
271
|
+
* and measure timing. Note: query SQL is generated before middleware runs, so
|
|
272
|
+
* modifying params.args in middleware will NOT affect the executed SQL.
|
|
273
|
+
* To intercept queries before SQL generation, use the raw() method instead.
|
|
227
274
|
*/
|
|
228
275
|
private executeWithMiddleware;
|
|
229
276
|
/**
|
|
@@ -305,13 +352,6 @@ export declare class QueryInterface<T extends object> {
|
|
|
305
352
|
private buildOrderBy;
|
|
306
353
|
/** Parse a flat row: convert snake_case to camelCase + Date coercion */
|
|
307
354
|
private parseRow;
|
|
308
|
-
/**
|
|
309
|
-
* Fast path: parse a flat row when the table has NO date columns.
|
|
310
|
-
* Only renames snake_case -> camelCase via the pre-computed reverseMap.
|
|
311
|
-
* Skips all date coercion checks — avoids Set.has() per field per row.
|
|
312
|
-
* Used by findUnique/findMany fast paths when hasNoDateColumns is true.
|
|
313
|
-
*/
|
|
314
|
-
private parseRowFast;
|
|
315
355
|
/** Parse a row that may contain JSON nested relation columns */
|
|
316
356
|
private parseNestedRow;
|
|
317
357
|
/**
|
|
@@ -338,6 +378,7 @@ export declare class QueryInterface<T extends object> {
|
|
|
338
378
|
/**
|
|
339
379
|
* Get the Postgres type for a column (e.g. 'jsonb', 'text', '_int4').
|
|
340
380
|
* Used to detect JSONB/array columns for specialized operators.
|
|
381
|
+
* Uses pre-computed Map for O(1) lookup instead of linear scan.
|
|
341
382
|
*/
|
|
342
383
|
private getColumnPgType;
|
|
343
384
|
/**
|
|
@@ -355,7 +396,10 @@ export declare class QueryInterface<T extends object> {
|
|
|
355
396
|
* Supports: has, hasEvery, hasSome, isEmpty.
|
|
356
397
|
*/
|
|
357
398
|
private buildArrayFilterClauses;
|
|
358
|
-
/**
|
|
399
|
+
/**
|
|
400
|
+
* Get the Postgres array type for a column (used by UNNEST in createMany).
|
|
401
|
+
* Uses pre-computed Map for O(1) lookup instead of linear scan.
|
|
402
|
+
*/
|
|
359
403
|
private getColumnArrayType;
|
|
360
404
|
}
|
|
361
405
|
export {};
|