@flowblade/sqlduck 0.13.0 → 0.14.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 +1 -1
- package/dist/duck-reserved-keywords-CUmaTbrD.mjs +118 -0
- package/dist/index.d.mts +9 -2
- package/dist/index.mjs +11 -6
- package/dist/{types-DCqYqEsa.d.mts → types-dnhcognF.d.mts} +7 -1
- package/dist/validation/valibot/index.d.mts +127 -0
- package/dist/validation/valibot/index.mjs +73 -0
- package/dist/validation/zod/index.d.mts +87 -12
- package/dist/validation/zod/index.mjs +2 -2
- package/dist/{zod-DcIc8xQC.mjs → zod-BRUUIdGW.mjs} +31 -135
- package/package.json +22 -10
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ import { conn } from "./db.config.ts";
|
|
|
29
29
|
|
|
30
30
|
const dbManager = new DuckDatabaseManager(conn);
|
|
31
31
|
const database = await dbManager.attach({
|
|
32
|
-
type: 'memory', // can be '
|
|
32
|
+
type: 'memory', // can be 'filesystem', ...
|
|
33
33
|
alias: 'mydb',
|
|
34
34
|
options: { COMPRESS: 'false' },
|
|
35
35
|
});
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
//#region src/validation/core/base-validators.ts
|
|
2
|
+
const duckIdentifierNameRegex = /^[a-z_]\w*$/i;
|
|
3
|
+
const duckStorageVersionRegexp = /^v?\d{1,4}\.\d{1,4}\.\d{1,4}$/;
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region src/validation/core/duck-connections-options.ts
|
|
6
|
+
const duckConnectionsOptions = { types: [
|
|
7
|
+
"DUCKDB",
|
|
8
|
+
"SQLITE",
|
|
9
|
+
"MYSQL",
|
|
10
|
+
"PostgreSQL"
|
|
11
|
+
] };
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/validation/core/duck-reserved-keywords.ts
|
|
14
|
+
/**
|
|
15
|
+
* DuckDB reserved keywords that cannot be used as unquoted identifiers.
|
|
16
|
+
* @see https://duckdb.org/docs/sql/keywords-and-identifiers.html
|
|
17
|
+
*/
|
|
18
|
+
const duckReservedKeywords = [
|
|
19
|
+
"ALL",
|
|
20
|
+
"ANALYSE",
|
|
21
|
+
"ANALYZE",
|
|
22
|
+
"AND",
|
|
23
|
+
"ANY",
|
|
24
|
+
"ARRAY",
|
|
25
|
+
"AS",
|
|
26
|
+
"ASC",
|
|
27
|
+
"ASYMMETRIC",
|
|
28
|
+
"BOTH",
|
|
29
|
+
"CASE",
|
|
30
|
+
"CAST",
|
|
31
|
+
"CHECK",
|
|
32
|
+
"COLLATE",
|
|
33
|
+
"COLUMN",
|
|
34
|
+
"CONSTRAINT",
|
|
35
|
+
"CREATE",
|
|
36
|
+
"CROSS",
|
|
37
|
+
"CURRENT_CATALOG",
|
|
38
|
+
"CURRENT_DATE",
|
|
39
|
+
"CURRENT_ROLE",
|
|
40
|
+
"CURRENT_SCHEMA",
|
|
41
|
+
"CURRENT_TIME",
|
|
42
|
+
"CURRENT_TIMESTAMP",
|
|
43
|
+
"CURRENT_USER",
|
|
44
|
+
"DEFAULT",
|
|
45
|
+
"DEFERRABLE",
|
|
46
|
+
"DESC",
|
|
47
|
+
"DISTINCT",
|
|
48
|
+
"DO",
|
|
49
|
+
"ELSE",
|
|
50
|
+
"END",
|
|
51
|
+
"EXCEPT",
|
|
52
|
+
"EXISTS",
|
|
53
|
+
"EXTRACT",
|
|
54
|
+
"FALSE",
|
|
55
|
+
"FETCH",
|
|
56
|
+
"FOR",
|
|
57
|
+
"FOREIGN",
|
|
58
|
+
"FROM",
|
|
59
|
+
"GRANT",
|
|
60
|
+
"GROUP",
|
|
61
|
+
"HAVING",
|
|
62
|
+
"IF",
|
|
63
|
+
"ILIKE",
|
|
64
|
+
"IN",
|
|
65
|
+
"INITIALLY",
|
|
66
|
+
"INNER",
|
|
67
|
+
"INTERSECT",
|
|
68
|
+
"INTO",
|
|
69
|
+
"IS",
|
|
70
|
+
"ISNULL",
|
|
71
|
+
"JOIN",
|
|
72
|
+
"LATERAL",
|
|
73
|
+
"LEADING",
|
|
74
|
+
"LEFT",
|
|
75
|
+
"LIKE",
|
|
76
|
+
"LIMIT",
|
|
77
|
+
"LOCALTIME",
|
|
78
|
+
"LOCALTIMESTAMP",
|
|
79
|
+
"NATURAL",
|
|
80
|
+
"NOT",
|
|
81
|
+
"NOTNULL",
|
|
82
|
+
"NULL",
|
|
83
|
+
"OFFSET",
|
|
84
|
+
"ON",
|
|
85
|
+
"ONLY",
|
|
86
|
+
"OR",
|
|
87
|
+
"ORDER",
|
|
88
|
+
"OUTER",
|
|
89
|
+
"OVERLAPS",
|
|
90
|
+
"PLACING",
|
|
91
|
+
"PRIMARY",
|
|
92
|
+
"REFERENCES",
|
|
93
|
+
"RETURNING",
|
|
94
|
+
"RIGHT",
|
|
95
|
+
"ROW",
|
|
96
|
+
"SELECT",
|
|
97
|
+
"SESSION_USER",
|
|
98
|
+
"SIMILAR",
|
|
99
|
+
"SOME",
|
|
100
|
+
"SYMMETRIC",
|
|
101
|
+
"TABLE",
|
|
102
|
+
"THEN",
|
|
103
|
+
"TO",
|
|
104
|
+
"TRAILING",
|
|
105
|
+
"TRUE",
|
|
106
|
+
"UNION",
|
|
107
|
+
"UNIQUE",
|
|
108
|
+
"USING",
|
|
109
|
+
"VARIADIC",
|
|
110
|
+
"VERBOSE",
|
|
111
|
+
"WHEN",
|
|
112
|
+
"WHERE",
|
|
113
|
+
"WINDOW",
|
|
114
|
+
"WITH"
|
|
115
|
+
];
|
|
116
|
+
const duckdbReservedKeywordsSet = new Set(duckReservedKeywords);
|
|
117
|
+
//#endregion
|
|
118
|
+
export { duckStorageVersionRegexp as a, duckIdentifierNameRegex as i, duckdbReservedKeywordsSet as n, duckConnectionsOptions as r, duckReservedKeywords as t };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as DuckConnectionParams } from "./types-
|
|
1
|
+
import { n as DuckConnectionParams } from "./types-dnhcognF.mjs";
|
|
2
2
|
import * as _$_duckdb_node_api0 from "@duckdb/node-api";
|
|
3
3
|
import { DuckDBConnection, DuckDBType } from "@duckdb/node-api";
|
|
4
4
|
import * as _$_logtape_logtape0 from "@logtape/logtape";
|
|
@@ -143,6 +143,13 @@ type ToTableParams<TSchema extends TableSchemaZod> = {
|
|
|
143
143
|
* @default true
|
|
144
144
|
*/
|
|
145
145
|
autoCheckpoint?: boolean;
|
|
146
|
+
/**
|
|
147
|
+
* Checkpoint the table after 'n' chunks have been appended
|
|
148
|
+
*
|
|
149
|
+
* For example if the chunkSize is 2048, setting frequency to 2
|
|
150
|
+
* will checkpoint the table every 4096 rows (2x chunksize)
|
|
151
|
+
*/
|
|
152
|
+
checkpointChunksFrequency?: number;
|
|
146
153
|
};
|
|
147
154
|
type ToTableResult = {
|
|
148
155
|
/**
|
|
@@ -251,7 +258,7 @@ declare class DuckDatabaseManager {
|
|
|
251
258
|
* ```typescript
|
|
252
259
|
* const dbManager = new DuckDatabaseManager(conn);
|
|
253
260
|
* const database = dbManager.attach({
|
|
254
|
-
* type: 'memory', // can be '
|
|
261
|
+
* type: 'memory', // can be 'filesystem'...
|
|
255
262
|
* alias: 'mydb',
|
|
256
263
|
* options: { COMPRESS: 'true' }
|
|
257
264
|
* });
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as duckReservedKeywords } from "./duck-reserved-keywords-CUmaTbrD.mjs";
|
|
2
|
+
import { n as assertValidAliasName, o as duckConnectionParamsZodSchema, s as duckValidatorsZod } from "./zod-BRUUIdGW.mjs";
|
|
2
3
|
import { BIGINT, BOOLEAN, DOUBLE, DuckDBDataChunk, DuckDBTimestampValue, FLOAT, HUGEINT, INTEGER, SMALLINT, TIMESTAMP, TINYINT, UBIGINT, UHUGEINT, UINTEGER, USMALLINT, UTINYINT, UUID, VARCHAR } from "@duckdb/node-api";
|
|
3
4
|
import { getLogger } from "@logtape/logtape";
|
|
4
5
|
import * as z from "zod";
|
|
@@ -163,7 +164,7 @@ var DuckDatabaseAttachCommand = class {
|
|
|
163
164
|
case "memory":
|
|
164
165
|
parts.push("':memory:'");
|
|
165
166
|
break;
|
|
166
|
-
case "
|
|
167
|
+
case "filesystem":
|
|
167
168
|
parts.push(`'${dbParams.path}'`);
|
|
168
169
|
break;
|
|
169
170
|
default: assertNever(type);
|
|
@@ -217,7 +218,7 @@ var DuckDatabaseManager = class {
|
|
|
217
218
|
* ```typescript
|
|
218
219
|
* const dbManager = new DuckDatabaseManager(conn);
|
|
219
220
|
* const database = dbManager.attach({
|
|
220
|
-
* type: 'memory', // can be '
|
|
221
|
+
* type: 'memory', // can be 'filesystem'...
|
|
221
222
|
* alias: 'mydb',
|
|
222
223
|
* options: { COMPRESS: 'true' }
|
|
223
224
|
* });
|
|
@@ -277,7 +278,7 @@ var DuckDatabaseManager = class {
|
|
|
277
278
|
const result = await this.#conn.runAndReadAll(rawSql);
|
|
278
279
|
const timeMs = Math.round(Date.now() - startTime);
|
|
279
280
|
const data = result.getRowObjectsJS();
|
|
280
|
-
this.#logger.
|
|
281
|
+
this.#logger.debug(`DuckDatabaseManager.${name} in ${timeMs}ms`, { timeMs });
|
|
281
282
|
return data;
|
|
282
283
|
} catch (e) {
|
|
283
284
|
const msg = `DuckDatabaseManager: failed to run "${name}" - ${e?.message ?? ""}`;
|
|
@@ -514,9 +515,11 @@ var SqlDuck = class {
|
|
|
514
515
|
* ```
|
|
515
516
|
*/
|
|
516
517
|
toTable = async (params) => {
|
|
517
|
-
const { table, schema, chunkSize = 2048, rowStream, createOptions, onDataAppended, autoCheckpoint = true } = params;
|
|
518
|
+
const { table, schema, chunkSize = 2048, rowStream, createOptions, onDataAppended, autoCheckpoint = true, checkpointChunksFrequency = 10 } = params;
|
|
518
519
|
if (!Number.isSafeInteger(chunkSize) || chunkSize < 1 || chunkSize > 2048) throw new Error("chunkSize must be a number between 1 and 2048");
|
|
519
520
|
if (autoCheckpoint && typeof table.databaseName !== "string") throw new Error("autoCheckpoint requires table.databaseName to be provided.");
|
|
521
|
+
if (checkpointChunksFrequency && typeof table.databaseName !== "string") throw new Error("checkpointChunksFrequency requires table.databaseName to be provided.");
|
|
522
|
+
if (checkpointChunksFrequency !== void 0 && checkpointChunksFrequency < 1) throw new Error("checkpointChunksFrequency must be a positive number.");
|
|
520
523
|
const dbManager = new DuckDatabaseManager(this.#conn);
|
|
521
524
|
const timeStart = Date.now();
|
|
522
525
|
const { columnTypes, ddl } = await createTableFromZod({
|
|
@@ -533,6 +536,7 @@ var SqlDuck = class {
|
|
|
533
536
|
rows: rowStream,
|
|
534
537
|
chunkSize
|
|
535
538
|
});
|
|
539
|
+
let appendedChunkCount = 0;
|
|
536
540
|
try {
|
|
537
541
|
for await (const dataChunk of columnStream) {
|
|
538
542
|
const chunk = DuckDBDataChunk.create(chunkTypes);
|
|
@@ -541,12 +545,13 @@ var SqlDuck = class {
|
|
|
541
545
|
chunk.setColumns(dataChunk);
|
|
542
546
|
appender.appendDataChunk(chunk);
|
|
543
547
|
appender.flushSync();
|
|
548
|
+
appendedChunkCount += 1;
|
|
544
549
|
if (onDataAppended !== void 0) {
|
|
545
550
|
const payload = dataAppendedCollector(totalRows);
|
|
546
551
|
if (isOnDataAppendedAsyncCb(onDataAppended)) await onDataAppended(payload);
|
|
547
552
|
else onDataAppended(payload);
|
|
548
553
|
}
|
|
549
|
-
if (
|
|
554
|
+
if (checkpointChunksFrequency !== void 0 && appendedChunkCount % checkpointChunksFrequency === 0 && typeof table.databaseName === "string") try {
|
|
550
555
|
await dbManager.checkpoint(table.databaseName);
|
|
551
556
|
} catch (e) {
|
|
552
557
|
this.#logger.warning(`Failed to checkpoint database '${table.databaseName}' after appending chunk into table '${table.getFullName()}' - ${e?.message ?? ""}`, { table: table.getFullName() });
|
|
@@ -10,6 +10,8 @@ declare const duckAllConnectionOptionsZodSchema: z.ZodObject<{
|
|
|
10
10
|
type: z.ZodOptional<z.ZodEnum<{
|
|
11
11
|
DUCKDB: "DUCKDB";
|
|
12
12
|
SQLITE: "SQLITE";
|
|
13
|
+
MYSQL: "MYSQL";
|
|
14
|
+
PostgreSQL: "PostgreSQL";
|
|
13
15
|
}>>;
|
|
14
16
|
blockSize: z.ZodOptional<z.ZodInt32>;
|
|
15
17
|
rowGroupSize: z.ZodOptional<z.ZodInt32>;
|
|
@@ -33,6 +35,8 @@ declare const duckConnectionParamsZodSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
|
|
|
33
35
|
type: z.ZodOptional<z.ZodEnum<{
|
|
34
36
|
DUCKDB: "DUCKDB";
|
|
35
37
|
SQLITE: "SQLITE";
|
|
38
|
+
MYSQL: "MYSQL";
|
|
39
|
+
PostgreSQL: "PostgreSQL";
|
|
36
40
|
}>>;
|
|
37
41
|
blockSize: z.ZodOptional<z.ZodInt32>;
|
|
38
42
|
rowGroupSize: z.ZodOptional<z.ZodInt32>;
|
|
@@ -45,7 +49,7 @@ declare const duckConnectionParamsZodSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
|
|
|
45
49
|
}>>;
|
|
46
50
|
}, z.core.$strict>>;
|
|
47
51
|
}, z.core.$strict>, z.ZodObject<{
|
|
48
|
-
type: z.ZodLiteral<"
|
|
52
|
+
type: z.ZodLiteral<"filesystem">;
|
|
49
53
|
path: z.ZodString;
|
|
50
54
|
alias: z.ZodString;
|
|
51
55
|
options: z.ZodOptional<z.ZodObject<{
|
|
@@ -57,6 +61,8 @@ declare const duckConnectionParamsZodSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
|
|
|
57
61
|
type: z.ZodOptional<z.ZodEnum<{
|
|
58
62
|
DUCKDB: "DUCKDB";
|
|
59
63
|
SQLITE: "SQLITE";
|
|
64
|
+
MYSQL: "MYSQL";
|
|
65
|
+
PostgreSQL: "PostgreSQL";
|
|
60
66
|
}>>;
|
|
61
67
|
blockSize: z.ZodOptional<z.ZodInt32>;
|
|
62
68
|
rowGroupSize: z.ZodOptional<z.ZodInt32>;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import * as v from "valibot";
|
|
2
|
+
|
|
3
|
+
//#region src/validation/valibot/duck-connection-params-valibot-schema.d.ts
|
|
4
|
+
declare const duckAllConnectionOptionsValibotSchema: v.ObjectSchema<{
|
|
5
|
+
readonly accessMode: v.OptionalSchema<v.PicklistSchema<["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
|
|
6
|
+
readonly compress: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
7
|
+
readonly type: v.OptionalSchema<v.PicklistSchema<readonly ["DUCKDB", "SQLITE", "MYSQL", "PostgreSQL"], undefined>, undefined>;
|
|
8
|
+
readonly blockSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 16384, undefined>, v.MaxValueAction<number, 262144, undefined>]>, undefined>;
|
|
9
|
+
readonly rowGroupSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, undefined>;
|
|
10
|
+
readonly storageVersion: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.StartsWithAction<string, "v", undefined>, v.RegexAction<string, undefined>]>, undefined>;
|
|
11
|
+
readonly encryptionKey: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 8, undefined>]>, undefined>;
|
|
12
|
+
readonly encryptionCipher: v.OptionalSchema<v.PicklistSchema<["CBC", "CTR", "GCM"], undefined>, undefined>;
|
|
13
|
+
}, undefined>;
|
|
14
|
+
type DuckAllConnectionOptionsValibotSchema = v.InferOutput<typeof duckAllConnectionOptionsValibotSchema>;
|
|
15
|
+
declare const duckConnectionParamsValibotSchema: v.VariantSchema<"type", [v.ObjectSchema<{
|
|
16
|
+
readonly type: v.LiteralSchema<"memory", undefined>;
|
|
17
|
+
readonly alias: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>, v.RegexAction<string, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores">, v.CheckAction<string, "Identifier value is a DuckDB reserved keyword and cannot be used as an identifier">]>;
|
|
18
|
+
readonly options: v.OptionalSchema<v.ObjectSchema<{
|
|
19
|
+
readonly accessMode: v.OptionalSchema<v.PicklistSchema<["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
|
|
20
|
+
readonly compress: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
21
|
+
readonly type: v.OptionalSchema<v.PicklistSchema<readonly ["DUCKDB", "SQLITE", "MYSQL", "PostgreSQL"], undefined>, undefined>;
|
|
22
|
+
readonly blockSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 16384, undefined>, v.MaxValueAction<number, 262144, undefined>]>, undefined>;
|
|
23
|
+
readonly rowGroupSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, undefined>;
|
|
24
|
+
readonly storageVersion: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.StartsWithAction<string, "v", undefined>, v.RegexAction<string, undefined>]>, undefined>;
|
|
25
|
+
readonly encryptionKey: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 8, undefined>]>, undefined>;
|
|
26
|
+
readonly encryptionCipher: v.OptionalSchema<v.PicklistSchema<["CBC", "CTR", "GCM"], undefined>, undefined>;
|
|
27
|
+
}, undefined>, undefined>;
|
|
28
|
+
}, undefined>, v.ObjectSchema<{
|
|
29
|
+
readonly type: v.LiteralSchema<"filesystem", undefined>;
|
|
30
|
+
readonly path: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, "Invalid database filename - it must be a safe filename (no path traversal, no absolute paths, no reserved names, etc.)">, v.CheckAction<string, "Invalid database pathname - it must be an absolute path with no traversal">]>;
|
|
31
|
+
readonly alias: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>, v.RegexAction<string, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores">, v.CheckAction<string, "Identifier value is a DuckDB reserved keyword and cannot be used as an identifier">]>;
|
|
32
|
+
readonly options: v.OptionalSchema<v.ObjectSchema<{
|
|
33
|
+
readonly accessMode: v.OptionalSchema<v.PicklistSchema<["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
|
|
34
|
+
readonly compress: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
35
|
+
readonly type: v.OptionalSchema<v.PicklistSchema<readonly ["DUCKDB", "SQLITE", "MYSQL", "PostgreSQL"], undefined>, undefined>;
|
|
36
|
+
readonly blockSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 16384, undefined>, v.MaxValueAction<number, 262144, undefined>]>, undefined>;
|
|
37
|
+
readonly rowGroupSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, undefined>;
|
|
38
|
+
readonly storageVersion: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.StartsWithAction<string, "v", undefined>, v.RegexAction<string, undefined>]>, undefined>;
|
|
39
|
+
readonly encryptionKey: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 8, undefined>]>, undefined>;
|
|
40
|
+
readonly encryptionCipher: v.OptionalSchema<v.PicklistSchema<["CBC", "CTR", "GCM"], undefined>, undefined>;
|
|
41
|
+
}, undefined>, undefined>;
|
|
42
|
+
}, undefined>], undefined>;
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/validation/valibot/duck-dsn-valibot-schema.d.ts
|
|
45
|
+
declare const duckDsnValibotSchema: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, (input: v.CheckIssue<string>) => string>, v.TransformAction<string, {
|
|
46
|
+
type: "memory";
|
|
47
|
+
alias: string;
|
|
48
|
+
options?: {
|
|
49
|
+
accessMode?: "READ_ONLY" | "READ_WRITE" | undefined;
|
|
50
|
+
compress?: boolean | undefined;
|
|
51
|
+
type?: "DUCKDB" | "SQLITE" | "MYSQL" | "PostgreSQL" | undefined;
|
|
52
|
+
blockSize?: number | undefined;
|
|
53
|
+
rowGroupSize?: number | undefined;
|
|
54
|
+
storageVersion?: string | undefined;
|
|
55
|
+
encryptionKey?: string | undefined;
|
|
56
|
+
encryptionCipher?: "CBC" | "CTR" | "GCM" | undefined;
|
|
57
|
+
} | undefined;
|
|
58
|
+
} | {
|
|
59
|
+
type: "filesystem";
|
|
60
|
+
path: string;
|
|
61
|
+
alias: string;
|
|
62
|
+
options?: {
|
|
63
|
+
accessMode?: "READ_ONLY" | "READ_WRITE" | undefined;
|
|
64
|
+
compress?: boolean | undefined;
|
|
65
|
+
type?: "DUCKDB" | "SQLITE" | "MYSQL" | "PostgreSQL" | undefined;
|
|
66
|
+
blockSize?: number | undefined;
|
|
67
|
+
rowGroupSize?: number | undefined;
|
|
68
|
+
storageVersion?: string | undefined;
|
|
69
|
+
encryptionKey?: string | undefined;
|
|
70
|
+
encryptionCipher?: "CBC" | "CTR" | "GCM" | undefined;
|
|
71
|
+
} | undefined;
|
|
72
|
+
}>, v.VariantSchema<"type", [v.ObjectSchema<{
|
|
73
|
+
readonly type: v.LiteralSchema<"memory", undefined>;
|
|
74
|
+
readonly alias: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>, v.RegexAction<string, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores">, v.CheckAction<string, "Identifier value is a DuckDB reserved keyword and cannot be used as an identifier">]>;
|
|
75
|
+
readonly options: v.OptionalSchema<v.ObjectSchema<{
|
|
76
|
+
readonly accessMode: v.OptionalSchema<v.PicklistSchema<["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
|
|
77
|
+
readonly compress: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
78
|
+
readonly type: v.OptionalSchema<v.PicklistSchema<readonly ["DUCKDB", "SQLITE", "MYSQL", "PostgreSQL"], undefined>, undefined>;
|
|
79
|
+
readonly blockSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 16384, undefined>, v.MaxValueAction<number, 262144, undefined>]>, undefined>;
|
|
80
|
+
readonly rowGroupSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, undefined>;
|
|
81
|
+
readonly storageVersion: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.StartsWithAction<string, "v", undefined>, v.RegexAction<string, undefined>]>, undefined>;
|
|
82
|
+
readonly encryptionKey: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 8, undefined>]>, undefined>;
|
|
83
|
+
readonly encryptionCipher: v.OptionalSchema<v.PicklistSchema<["CBC", "CTR", "GCM"], undefined>, undefined>;
|
|
84
|
+
}, undefined>, undefined>;
|
|
85
|
+
}, undefined>, v.ObjectSchema<{
|
|
86
|
+
readonly type: v.LiteralSchema<"filesystem", undefined>;
|
|
87
|
+
readonly path: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, "Invalid database filename - it must be a safe filename (no path traversal, no absolute paths, no reserved names, etc.)">, v.CheckAction<string, "Invalid database pathname - it must be an absolute path with no traversal">]>;
|
|
88
|
+
readonly alias: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>, v.RegexAction<string, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores">, v.CheckAction<string, "Identifier value is a DuckDB reserved keyword and cannot be used as an identifier">]>;
|
|
89
|
+
readonly options: v.OptionalSchema<v.ObjectSchema<{
|
|
90
|
+
readonly accessMode: v.OptionalSchema<v.PicklistSchema<["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
|
|
91
|
+
readonly compress: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
92
|
+
readonly type: v.OptionalSchema<v.PicklistSchema<readonly ["DUCKDB", "SQLITE", "MYSQL", "PostgreSQL"], undefined>, undefined>;
|
|
93
|
+
readonly blockSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 16384, undefined>, v.MaxValueAction<number, 262144, undefined>]>, undefined>;
|
|
94
|
+
readonly rowGroupSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, undefined>;
|
|
95
|
+
readonly storageVersion: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.StartsWithAction<string, "v", undefined>, v.RegexAction<string, undefined>]>, undefined>;
|
|
96
|
+
readonly encryptionKey: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 8, undefined>]>, undefined>;
|
|
97
|
+
readonly encryptionCipher: v.OptionalSchema<v.PicklistSchema<["CBC", "CTR", "GCM"], undefined>, undefined>;
|
|
98
|
+
}, undefined>, undefined>;
|
|
99
|
+
}, undefined>], undefined>]>;
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/validation/valibot/duck-identifier-valibot-schema.d.ts
|
|
102
|
+
/**
|
|
103
|
+
* Check whether a table name identifier is valid
|
|
104
|
+
*/
|
|
105
|
+
declare const duckIdentifierValibotSchema: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>, v.RegexAction<string, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores">, v.CheckAction<string, "Identifier value is a DuckDB reserved keyword and cannot be used as an identifier">]>;
|
|
106
|
+
//#endregion
|
|
107
|
+
//#region src/validation/valibot/duck-validators-valibot.d.ts
|
|
108
|
+
/**
|
|
109
|
+
* Common validators for duckdb parameters, tables...
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```typescript
|
|
113
|
+
* import { duckValidatorsValibot } from '@flowblade/sqlduck/valibot';
|
|
114
|
+
*
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
declare const duckValidatorsValibot: {
|
|
118
|
+
/**
|
|
119
|
+
* Validate duckdb objects names like table, alias, and schemas
|
|
120
|
+
* for validity.
|
|
121
|
+
*/
|
|
122
|
+
readonly aliasName: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>, v.RegexAction<string, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores">, v.CheckAction<string, "Identifier value is a DuckDB reserved keyword and cannot be used as an identifier">]>;
|
|
123
|
+
readonly schemaName: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>, v.RegexAction<string, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores">, v.CheckAction<string, "Identifier value is a DuckDB reserved keyword and cannot be used as an identifier">]>;
|
|
124
|
+
readonly tableName: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>, v.RegexAction<string, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores">, v.CheckAction<string, "Identifier value is a DuckDB reserved keyword and cannot be used as an identifier">]>;
|
|
125
|
+
};
|
|
126
|
+
//#endregion
|
|
127
|
+
export { type DuckAllConnectionOptionsValibotSchema, duckAllConnectionOptionsValibotSchema, duckConnectionParamsValibotSchema, duckDsnValibotSchema, duckIdentifierValibotSchema, duckValidatorsValibot };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { a as duckStorageVersionRegexp, i as duckIdentifierNameRegex, n as duckdbReservedKeywordsSet, r as duckConnectionsOptions } from "../../duck-reserved-keywords-CUmaTbrD.mjs";
|
|
2
|
+
import isSafeFilename from "is-safe-filename";
|
|
3
|
+
import { parseDsn, parseDsnOrThrow } from "@httpx/dsn-parser";
|
|
4
|
+
import * as v from "valibot";
|
|
5
|
+
//#region src/validation/valibot/duck-identifier-valibot-schema.ts
|
|
6
|
+
/**
|
|
7
|
+
* Check whether a table name identifier is valid
|
|
8
|
+
*/
|
|
9
|
+
const duckIdentifierValibotSchema = v.pipe(v.string(), v.minLength(1), v.maxLength(120), v.regex(duckIdentifierNameRegex, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores"), v.check((value) => !duckdbReservedKeywordsSet.has(value.toUpperCase()), "Identifier value is a DuckDB reserved keyword and cannot be used as an identifier"));
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/validation/valibot/duck-validators-valibot.ts
|
|
12
|
+
/**
|
|
13
|
+
* Common validators for duckdb parameters, tables...
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* import { duckValidatorsValibot } from '@flowblade/sqlduck/valibot';
|
|
18
|
+
*
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
const duckValidatorsValibot = {
|
|
22
|
+
aliasName: duckIdentifierValibotSchema,
|
|
23
|
+
schemaName: duckIdentifierValibotSchema,
|
|
24
|
+
tableName: duckIdentifierValibotSchema
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/validation/valibot/duck-connection-params-valibot-schema.ts
|
|
28
|
+
const duckAllConnectionOptionsValibotSchema = v.object({
|
|
29
|
+
accessMode: v.optional(v.picklist(["READ_ONLY", "READ_WRITE"])),
|
|
30
|
+
compress: v.optional(v.boolean()),
|
|
31
|
+
type: v.optional(v.picklist(duckConnectionsOptions.types)),
|
|
32
|
+
blockSize: v.optional(v.pipe(v.number(), v.integer(), v.minValue(16384), v.maxValue(262144))),
|
|
33
|
+
rowGroupSize: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1))),
|
|
34
|
+
storageVersion: v.optional(v.pipe(v.string(), v.startsWith("v"), v.regex(duckStorageVersionRegexp))),
|
|
35
|
+
encryptionKey: v.optional(v.pipe(v.string(), v.minLength(8))),
|
|
36
|
+
encryptionCipher: v.optional(v.picklist([
|
|
37
|
+
"CBC",
|
|
38
|
+
"CTR",
|
|
39
|
+
"GCM"
|
|
40
|
+
]))
|
|
41
|
+
});
|
|
42
|
+
const duckConnectionParamsValibotSchema = v.variant("type", [v.object({
|
|
43
|
+
type: v.literal("memory"),
|
|
44
|
+
alias: duckValidatorsValibot.aliasName,
|
|
45
|
+
options: v.optional(duckAllConnectionOptionsValibotSchema)
|
|
46
|
+
}), v.object({
|
|
47
|
+
type: v.literal("filesystem"),
|
|
48
|
+
path: v.pipe(v.string(), v.check((path) => {
|
|
49
|
+
const filename = path.replace("\\", "/").split("/").at(-1);
|
|
50
|
+
return typeof filename === "string" && isSafeFilename(filename);
|
|
51
|
+
}, "Invalid database filename - it must be a safe filename (no path traversal, no absolute paths, no reserved names, etc.)"), v.check((path) => {
|
|
52
|
+
const pathname = "/" + path.replace("\\", "/").split("/").slice(0, -1).filter(Boolean).join("/");
|
|
53
|
+
return pathname.length > 0 && pathname.startsWith("/") && !pathname.includes("..");
|
|
54
|
+
}, "Invalid database pathname - it must be an absolute path with no traversal")),
|
|
55
|
+
alias: duckValidatorsValibot.aliasName,
|
|
56
|
+
options: v.optional(duckAllConnectionOptionsValibotSchema)
|
|
57
|
+
})]);
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/validation/valibot/duck-dsn-valibot-schema.ts
|
|
60
|
+
const duckDsnValibotSchema = v.pipe(v.string(), v.check((dsn) => parseDsn(dsn).success, (input) => {
|
|
61
|
+
return parseDsn(input.input)?.message ?? "Invalid DSN";
|
|
62
|
+
}), v.transform((dsn) => {
|
|
63
|
+
const parsed = parseDsnOrThrow(dsn);
|
|
64
|
+
const { path, ...options } = parsed.params ?? {};
|
|
65
|
+
return {
|
|
66
|
+
type: parsed.host,
|
|
67
|
+
alias: parsed.db,
|
|
68
|
+
...path ? { path } : {},
|
|
69
|
+
options: { ...options }
|
|
70
|
+
};
|
|
71
|
+
}), duckConnectionParamsValibotSchema);
|
|
72
|
+
//#endregion
|
|
73
|
+
export { duckAllConnectionOptionsValibotSchema, duckConnectionParamsValibotSchema, duckDsnValibotSchema, duckIdentifierValibotSchema, duckValidatorsValibot };
|
|
@@ -1,11 +1,92 @@
|
|
|
1
|
-
import { a as duckAllConnectionOptionsZodSchema, i as DuckTableName,
|
|
2
|
-
import * as
|
|
1
|
+
import { a as duckAllConnectionOptionsZodSchema, i as DuckTableName, o as duckConnectionParamsZodSchema, r as DuckSchemaName, t as DuckAliasName } from "../../types-dnhcognF.mjs";
|
|
2
|
+
import * as z from "zod";
|
|
3
3
|
|
|
4
4
|
//#region src/validation/zod/duck-asserts-zod.d.ts
|
|
5
5
|
declare function assertValidAliasName(aliasName: string): asserts aliasName is DuckAliasName;
|
|
6
6
|
declare function assertValidSchemaName(schemaName: string): asserts schemaName is DuckSchemaName;
|
|
7
7
|
declare function assertValidTableName(tableName: string): asserts tableName is DuckTableName;
|
|
8
8
|
//#endregion
|
|
9
|
+
//#region src/validation/zod/duck-dsn-zod-schema.d.ts
|
|
10
|
+
declare const duckDsnZodSchema: z.ZodPipe<z.ZodString, z.ZodPipe<z.ZodTransform<{
|
|
11
|
+
type: "memory";
|
|
12
|
+
alias: string;
|
|
13
|
+
options?: {
|
|
14
|
+
accessMode?: "READ_ONLY" | "READ_WRITE" | undefined;
|
|
15
|
+
compress?: boolean | undefined;
|
|
16
|
+
type?: "DUCKDB" | "SQLITE" | "MYSQL" | "PostgreSQL" | undefined;
|
|
17
|
+
blockSize?: number | undefined;
|
|
18
|
+
rowGroupSize?: number | undefined;
|
|
19
|
+
storageVersion?: string | undefined;
|
|
20
|
+
encryptionKey?: string | undefined;
|
|
21
|
+
encryptionCipher?: "CBC" | "CTR" | "GCM" | undefined;
|
|
22
|
+
} | undefined;
|
|
23
|
+
} | {
|
|
24
|
+
type: "filesystem";
|
|
25
|
+
path: string;
|
|
26
|
+
alias: string;
|
|
27
|
+
options?: {
|
|
28
|
+
accessMode?: "READ_ONLY" | "READ_WRITE" | undefined;
|
|
29
|
+
compress?: boolean | undefined;
|
|
30
|
+
type?: "DUCKDB" | "SQLITE" | "MYSQL" | "PostgreSQL" | undefined;
|
|
31
|
+
blockSize?: number | undefined;
|
|
32
|
+
rowGroupSize?: number | undefined;
|
|
33
|
+
storageVersion?: string | undefined;
|
|
34
|
+
encryptionKey?: string | undefined;
|
|
35
|
+
encryptionCipher?: "CBC" | "CTR" | "GCM" | undefined;
|
|
36
|
+
} | undefined;
|
|
37
|
+
}, string>, z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
38
|
+
type: z.ZodLiteral<"memory">;
|
|
39
|
+
alias: z.ZodString;
|
|
40
|
+
options: z.ZodOptional<z.ZodObject<{
|
|
41
|
+
accessMode: z.ZodOptional<z.ZodEnum<{
|
|
42
|
+
READ_ONLY: "READ_ONLY";
|
|
43
|
+
READ_WRITE: "READ_WRITE";
|
|
44
|
+
}>>;
|
|
45
|
+
compress: z.ZodOptional<z.ZodBoolean>;
|
|
46
|
+
type: z.ZodOptional<z.ZodEnum<{
|
|
47
|
+
DUCKDB: "DUCKDB";
|
|
48
|
+
SQLITE: "SQLITE";
|
|
49
|
+
MYSQL: "MYSQL";
|
|
50
|
+
PostgreSQL: "PostgreSQL";
|
|
51
|
+
}>>;
|
|
52
|
+
blockSize: z.ZodOptional<z.ZodInt32>;
|
|
53
|
+
rowGroupSize: z.ZodOptional<z.ZodInt32>;
|
|
54
|
+
storageVersion: z.ZodOptional<z.ZodString>;
|
|
55
|
+
encryptionKey: z.ZodOptional<z.ZodString>;
|
|
56
|
+
encryptionCipher: z.ZodOptional<z.ZodEnum<{
|
|
57
|
+
CBC: "CBC";
|
|
58
|
+
CTR: "CTR";
|
|
59
|
+
GCM: "GCM";
|
|
60
|
+
}>>;
|
|
61
|
+
}, z.core.$strict>>;
|
|
62
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
63
|
+
type: z.ZodLiteral<"filesystem">;
|
|
64
|
+
path: z.ZodString;
|
|
65
|
+
alias: z.ZodString;
|
|
66
|
+
options: z.ZodOptional<z.ZodObject<{
|
|
67
|
+
accessMode: z.ZodOptional<z.ZodEnum<{
|
|
68
|
+
READ_ONLY: "READ_ONLY";
|
|
69
|
+
READ_WRITE: "READ_WRITE";
|
|
70
|
+
}>>;
|
|
71
|
+
compress: z.ZodOptional<z.ZodBoolean>;
|
|
72
|
+
type: z.ZodOptional<z.ZodEnum<{
|
|
73
|
+
DUCKDB: "DUCKDB";
|
|
74
|
+
SQLITE: "SQLITE";
|
|
75
|
+
MYSQL: "MYSQL";
|
|
76
|
+
PostgreSQL: "PostgreSQL";
|
|
77
|
+
}>>;
|
|
78
|
+
blockSize: z.ZodOptional<z.ZodInt32>;
|
|
79
|
+
rowGroupSize: z.ZodOptional<z.ZodInt32>;
|
|
80
|
+
storageVersion: z.ZodOptional<z.ZodString>;
|
|
81
|
+
encryptionKey: z.ZodOptional<z.ZodString>;
|
|
82
|
+
encryptionCipher: z.ZodOptional<z.ZodEnum<{
|
|
83
|
+
CBC: "CBC";
|
|
84
|
+
CTR: "CTR";
|
|
85
|
+
GCM: "GCM";
|
|
86
|
+
}>>;
|
|
87
|
+
}, z.core.$strict>>;
|
|
88
|
+
}, z.core.$strict>], "type">>>;
|
|
89
|
+
//#endregion
|
|
9
90
|
//#region src/validation/zod/duck-validators-zod.d.ts
|
|
10
91
|
/**
|
|
11
92
|
* Common validators for duckdb parameters, tables...
|
|
@@ -23,15 +104,9 @@ declare const duckValidatorsZod: {
|
|
|
23
104
|
* Validate duckdb objects names like table, alias, and schemas
|
|
24
105
|
* for validity.
|
|
25
106
|
*/
|
|
26
|
-
readonly aliasName:
|
|
27
|
-
readonly schemaName:
|
|
28
|
-
readonly tableName:
|
|
107
|
+
readonly aliasName: z.ZodString;
|
|
108
|
+
readonly schemaName: z.ZodString;
|
|
109
|
+
readonly tableName: z.ZodString;
|
|
29
110
|
};
|
|
30
111
|
//#endregion
|
|
31
|
-
|
|
32
|
-
declare const isParsableDuckDsnZod: (dsn: unknown) => boolean;
|
|
33
|
-
//#endregion
|
|
34
|
-
//#region src/validation/zod/parse-duck-dsn-zod.d.ts
|
|
35
|
-
declare const parseDuckDSNZod: (dsn: string) => DuckConnectionParams;
|
|
36
|
-
//#endregion
|
|
37
|
-
export { assertValidAliasName, assertValidSchemaName, assertValidTableName, duckAllConnectionOptionsZodSchema, duckConnectionParamsZodSchema, duckValidatorsZod, isParsableDuckDsnZod, parseDuckDSNZod };
|
|
112
|
+
export { assertValidAliasName, assertValidSchemaName, assertValidTableName, duckAllConnectionOptionsZodSchema, duckConnectionParamsZodSchema, duckDsnZodSchema, duckValidatorsZod };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { assertValidAliasName, assertValidSchemaName, assertValidTableName, duckAllConnectionOptionsZodSchema, duckConnectionParamsZodSchema,
|
|
1
|
+
import { a as duckAllConnectionOptionsZodSchema, i as assertValidTableName, n as assertValidAliasName, o as duckConnectionParamsZodSchema, r as assertValidSchemaName, s as duckValidatorsZod, t as duckDsnZodSchema } from "../../zod-BRUUIdGW.mjs";
|
|
2
|
+
export { assertValidAliasName, assertValidSchemaName, assertValidTableName, duckAllConnectionOptionsZodSchema, duckConnectionParamsZodSchema, duckDsnZodSchema, duckValidatorsZod };
|
|
@@ -1,115 +1,8 @@
|
|
|
1
|
+
import { a as duckStorageVersionRegexp, i as duckIdentifierNameRegex, n as duckdbReservedKeywordsSet, r as duckConnectionsOptions } from "./duck-reserved-keywords-CUmaTbrD.mjs";
|
|
2
|
+
import isSafeFilename from "is-safe-filename";
|
|
1
3
|
import * as z from "zod";
|
|
2
4
|
import { parseDsn } from "@httpx/dsn-parser";
|
|
3
|
-
//#region src/validation/core/base-validators.ts
|
|
4
|
-
const duckIdentifierNameRegex = /^[a-z_]\w*$/i;
|
|
5
|
-
const duckStorageVersionRegexp = /^v?\d{1,4}\.\d{1,4}\.\d{1,4}$/;
|
|
6
|
-
//#endregion
|
|
7
|
-
//#region src/validation/core/duck-reserved-keywords.ts
|
|
8
|
-
/**
|
|
9
|
-
* DuckDB reserved keywords that cannot be used as unquoted identifiers.
|
|
10
|
-
* @see https://duckdb.org/docs/sql/keywords-and-identifiers.html
|
|
11
|
-
*/
|
|
12
|
-
const duckReservedKeywords = [
|
|
13
|
-
"ALL",
|
|
14
|
-
"ANALYSE",
|
|
15
|
-
"ANALYZE",
|
|
16
|
-
"AND",
|
|
17
|
-
"ANY",
|
|
18
|
-
"ARRAY",
|
|
19
|
-
"AS",
|
|
20
|
-
"ASC",
|
|
21
|
-
"ASYMMETRIC",
|
|
22
|
-
"BOTH",
|
|
23
|
-
"CASE",
|
|
24
|
-
"CAST",
|
|
25
|
-
"CHECK",
|
|
26
|
-
"COLLATE",
|
|
27
|
-
"COLUMN",
|
|
28
|
-
"CONSTRAINT",
|
|
29
|
-
"CREATE",
|
|
30
|
-
"CROSS",
|
|
31
|
-
"CURRENT_CATALOG",
|
|
32
|
-
"CURRENT_DATE",
|
|
33
|
-
"CURRENT_ROLE",
|
|
34
|
-
"CURRENT_SCHEMA",
|
|
35
|
-
"CURRENT_TIME",
|
|
36
|
-
"CURRENT_TIMESTAMP",
|
|
37
|
-
"CURRENT_USER",
|
|
38
|
-
"DEFAULT",
|
|
39
|
-
"DEFERRABLE",
|
|
40
|
-
"DESC",
|
|
41
|
-
"DISTINCT",
|
|
42
|
-
"DO",
|
|
43
|
-
"ELSE",
|
|
44
|
-
"END",
|
|
45
|
-
"EXCEPT",
|
|
46
|
-
"EXISTS",
|
|
47
|
-
"EXTRACT",
|
|
48
|
-
"FALSE",
|
|
49
|
-
"FETCH",
|
|
50
|
-
"FOR",
|
|
51
|
-
"FOREIGN",
|
|
52
|
-
"FROM",
|
|
53
|
-
"GRANT",
|
|
54
|
-
"GROUP",
|
|
55
|
-
"HAVING",
|
|
56
|
-
"IF",
|
|
57
|
-
"ILIKE",
|
|
58
|
-
"IN",
|
|
59
|
-
"INITIALLY",
|
|
60
|
-
"INNER",
|
|
61
|
-
"INTERSECT",
|
|
62
|
-
"INTO",
|
|
63
|
-
"IS",
|
|
64
|
-
"ISNULL",
|
|
65
|
-
"JOIN",
|
|
66
|
-
"LATERAL",
|
|
67
|
-
"LEADING",
|
|
68
|
-
"LEFT",
|
|
69
|
-
"LIKE",
|
|
70
|
-
"LIMIT",
|
|
71
|
-
"LOCALTIME",
|
|
72
|
-
"LOCALTIMESTAMP",
|
|
73
|
-
"NATURAL",
|
|
74
|
-
"NOT",
|
|
75
|
-
"NOTNULL",
|
|
76
|
-
"NULL",
|
|
77
|
-
"OFFSET",
|
|
78
|
-
"ON",
|
|
79
|
-
"ONLY",
|
|
80
|
-
"OR",
|
|
81
|
-
"ORDER",
|
|
82
|
-
"OUTER",
|
|
83
|
-
"OVERLAPS",
|
|
84
|
-
"PLACING",
|
|
85
|
-
"PRIMARY",
|
|
86
|
-
"REFERENCES",
|
|
87
|
-
"RETURNING",
|
|
88
|
-
"RIGHT",
|
|
89
|
-
"ROW",
|
|
90
|
-
"SELECT",
|
|
91
|
-
"SESSION_USER",
|
|
92
|
-
"SIMILAR",
|
|
93
|
-
"SOME",
|
|
94
|
-
"SYMMETRIC",
|
|
95
|
-
"TABLE",
|
|
96
|
-
"THEN",
|
|
97
|
-
"TO",
|
|
98
|
-
"TRAILING",
|
|
99
|
-
"TRUE",
|
|
100
|
-
"UNION",
|
|
101
|
-
"UNIQUE",
|
|
102
|
-
"USING",
|
|
103
|
-
"VARIADIC",
|
|
104
|
-
"VERBOSE",
|
|
105
|
-
"WHEN",
|
|
106
|
-
"WHERE",
|
|
107
|
-
"WINDOW",
|
|
108
|
-
"WITH"
|
|
109
|
-
];
|
|
110
|
-
//#endregion
|
|
111
5
|
//#region src/validation/zod/duck-identifier-zod-schema.ts
|
|
112
|
-
const duckdbReservedKeywordsSet = new Set(duckReservedKeywords.map((k) => k.toUpperCase()));
|
|
113
6
|
/**
|
|
114
7
|
* Check whether a table name identifier is valid
|
|
115
8
|
*/
|
|
@@ -137,7 +30,7 @@ const duckValidatorsZod = {
|
|
|
137
30
|
const duckAllConnectionOptionsZodSchema = z.strictObject({
|
|
138
31
|
accessMode: z.optional(z.enum(["READ_ONLY", "READ_WRITE"])),
|
|
139
32
|
compress: z.optional(z.boolean()),
|
|
140
|
-
type: z.optional(z.enum(
|
|
33
|
+
type: z.optional(z.enum(duckConnectionsOptions.types)),
|
|
141
34
|
blockSize: z.optional(z.int32().min(16384).max(262144)),
|
|
142
35
|
rowGroupSize: z.optional(z.int32().positive()),
|
|
143
36
|
storageVersion: z.optional(z.string().startsWith("v").regex(duckStorageVersionRegexp)),
|
|
@@ -153,8 +46,14 @@ const duckConnectionParamsZodSchema = z.discriminatedUnion("type", [z.strictObje
|
|
|
153
46
|
alias: duckValidatorsZod.aliasName,
|
|
154
47
|
options: z.optional(duckAllConnectionOptionsZodSchema)
|
|
155
48
|
}), z.strictObject({
|
|
156
|
-
type: z.literal("
|
|
157
|
-
path: z.string().
|
|
49
|
+
type: z.literal("filesystem"),
|
|
50
|
+
path: z.string().refine((path) => {
|
|
51
|
+
const filename = path.replace("\\", "/").split("/").at(-1);
|
|
52
|
+
return typeof filename === "string" && isSafeFilename(filename);
|
|
53
|
+
}, { message: "Invalid database filename - it must be a safe filename (no path traversal, no absolute paths, no reserved names, etc.)" }).refine((path) => {
|
|
54
|
+
const pathname = "/" + path.replace("\\", "/").split("/").slice(0, -1).filter(Boolean).join("/");
|
|
55
|
+
return pathname.length > 0 && pathname.startsWith("/") && pathname.includes("..") === false;
|
|
56
|
+
}, { message: "Invalid database pathname - it must be an absolute path with no traversal" }),
|
|
158
57
|
alias: duckValidatorsZod.aliasName,
|
|
159
58
|
options: z.optional(duckAllConnectionOptionsZodSchema)
|
|
160
59
|
})]);
|
|
@@ -179,29 +78,26 @@ function assertValidTableName(tableName) {
|
|
|
179
78
|
if (parsed.error) throw createAssertError(`'${tableName}' is not a valid table name: ${parsed.error.message}`);
|
|
180
79
|
}
|
|
181
80
|
//#endregion
|
|
182
|
-
//#region src/validation/zod/
|
|
183
|
-
const
|
|
81
|
+
//#region src/validation/zod/duck-dsn-zod-schema.ts
|
|
82
|
+
const duckDsnZodSchema = z.string().pipe(z.preprocess((dsn, ctx) => {
|
|
184
83
|
const result = parseDsn(dsn);
|
|
185
|
-
if (
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
return true;
|
|
202
|
-
} catch {
|
|
203
|
-
return false;
|
|
84
|
+
if (result.success) {
|
|
85
|
+
const parsed = result.value;
|
|
86
|
+
const { path, ...options } = parsed.params ?? {};
|
|
87
|
+
return {
|
|
88
|
+
type: parsed.host,
|
|
89
|
+
alias: parsed.db,
|
|
90
|
+
...path ? { path } : {},
|
|
91
|
+
options: { ...options }
|
|
92
|
+
};
|
|
93
|
+
} else {
|
|
94
|
+
ctx.issues.push({
|
|
95
|
+
code: "custom",
|
|
96
|
+
message: result.message,
|
|
97
|
+
input: dsn
|
|
98
|
+
});
|
|
99
|
+
return z.NEVER;
|
|
204
100
|
}
|
|
205
|
-
};
|
|
101
|
+
}, duckConnectionParamsZodSchema));
|
|
206
102
|
//#endregion
|
|
207
|
-
export {
|
|
103
|
+
export { duckAllConnectionOptionsZodSchema as a, assertValidTableName as i, assertValidAliasName as n, duckConnectionParamsZodSchema as o, assertValidSchemaName as r, duckValidatorsZod as s, duckDsnZodSchema as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowblade/sqlduck",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"exports": {
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
"types": "./dist/validation/zod/index.d.mts",
|
|
13
13
|
"default": "./dist/validation/zod/index.mjs"
|
|
14
14
|
},
|
|
15
|
+
"./valibot": {
|
|
16
|
+
"types": "./dist/validation/valibot/index.d.mts",
|
|
17
|
+
"default": "./dist/validation/valibot/index.mjs"
|
|
18
|
+
},
|
|
15
19
|
"./package.json": "./package.json"
|
|
16
20
|
},
|
|
17
21
|
"author": {
|
|
@@ -55,42 +59,49 @@
|
|
|
55
59
|
"@flowblade/core": "^0.2.26",
|
|
56
60
|
"@flowblade/source-duckdb": "^0.20.1",
|
|
57
61
|
"@flowblade/sql-tag": "^0.3.2",
|
|
58
|
-
"@httpx/assert": "^0.16.
|
|
62
|
+
"@httpx/assert": "^0.16.9",
|
|
59
63
|
"@httpx/dsn-parser": "^1.9.9",
|
|
60
64
|
"@httpx/plain-object": "^2.1.8",
|
|
61
65
|
"@logtape/logtape": "^2.0.5",
|
|
62
66
|
"@standard-schema/spec": "^1.1.0",
|
|
63
|
-
"
|
|
67
|
+
"is-safe-filename": "0.1.1",
|
|
68
|
+
"p-queue": "9.1.1",
|
|
64
69
|
"zod": "^4.3.6"
|
|
65
70
|
},
|
|
66
71
|
"peerDependencies": {
|
|
67
|
-
"@duckdb/node-api": "^1.5.0-r.1"
|
|
72
|
+
"@duckdb/node-api": "^1.5.0-r.1",
|
|
73
|
+
"valibot": "^1.3.1"
|
|
74
|
+
},
|
|
75
|
+
"peerDependenciesMeta": {
|
|
76
|
+
"valibot": {
|
|
77
|
+
"optional": true
|
|
78
|
+
}
|
|
68
79
|
},
|
|
69
80
|
"devDependencies": {
|
|
70
|
-
"@belgattitude/eslint-config-bases": "8.
|
|
81
|
+
"@belgattitude/eslint-config-bases": "8.12.0",
|
|
71
82
|
"@dotenvx/dotenvx": "1.59.1",
|
|
72
83
|
"@duckdb/node-api": "1.5.1-r.1",
|
|
73
84
|
"@faker-js/faker": "10.4.0",
|
|
74
85
|
"@flowblade/source-kysely": "^1.3.0",
|
|
75
|
-
"@httpx/assert": "0.16.
|
|
86
|
+
"@httpx/assert": "0.16.9",
|
|
76
87
|
"@mitata/counters": "0.0.8",
|
|
77
88
|
"@size-limit/esbuild": "12.0.1",
|
|
78
89
|
"@size-limit/file": "12.0.1",
|
|
79
90
|
"@testcontainers/mssqlserver": "11.13.0",
|
|
80
91
|
"@total-typescript/ts-reset": "0.6.1",
|
|
81
|
-
"@types/node": "25.5.
|
|
92
|
+
"@types/node": "25.5.2",
|
|
82
93
|
"@typescript-eslint/eslint-plugin": "8.58.0",
|
|
83
94
|
"@typescript-eslint/parser": "8.58.0",
|
|
84
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
95
|
+
"@typescript/native-preview": "7.0.0-dev.20260406.1",
|
|
85
96
|
"@vitest/coverage-v8": "4.1.2",
|
|
86
97
|
"@vitest/ui": "4.1.2",
|
|
87
98
|
"ansis": "4.2.0",
|
|
88
99
|
"browserslist-to-esbuild": "2.1.1",
|
|
89
100
|
"core-js": "3.49.0",
|
|
90
101
|
"cross-env": "10.1.0",
|
|
91
|
-
"es-check": "9.6.
|
|
102
|
+
"es-check": "9.6.4",
|
|
92
103
|
"es-toolkit": "1.45.1",
|
|
93
|
-
"esbuild": "0.
|
|
104
|
+
"esbuild": "0.28.0",
|
|
94
105
|
"eslint": "8.57.1",
|
|
95
106
|
"execa": "9.6.1",
|
|
96
107
|
"is-in-ci": "2.0.0",
|
|
@@ -111,6 +122,7 @@
|
|
|
111
122
|
"typedoc": "0.28.18",
|
|
112
123
|
"typedoc-plugin-markdown": "4.11.0",
|
|
113
124
|
"typescript": "6.0.2",
|
|
125
|
+
"valibot": "1.3.1",
|
|
114
126
|
"vitest": "4.1.2"
|
|
115
127
|
},
|
|
116
128
|
"files": [
|