@flowblade/sqlduck 0.12.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 +20 -11
- 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-CwR_oehs.mjs → zod-BRUUIdGW.mjs} +50 -154
- 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,8 +515,12 @@ 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");
|
|
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.");
|
|
523
|
+
const dbManager = new DuckDatabaseManager(this.#conn);
|
|
519
524
|
const timeStart = Date.now();
|
|
520
525
|
const { columnTypes, ddl } = await createTableFromZod({
|
|
521
526
|
conn: this.#conn,
|
|
@@ -531,6 +536,7 @@ var SqlDuck = class {
|
|
|
531
536
|
rows: rowStream,
|
|
532
537
|
chunkSize
|
|
533
538
|
});
|
|
539
|
+
let appendedChunkCount = 0;
|
|
534
540
|
try {
|
|
535
541
|
for await (const dataChunk of columnStream) {
|
|
536
542
|
const chunk = DuckDBDataChunk.create(chunkTypes);
|
|
@@ -539,21 +545,24 @@ var SqlDuck = class {
|
|
|
539
545
|
chunk.setColumns(dataChunk);
|
|
540
546
|
appender.appendDataChunk(chunk);
|
|
541
547
|
appender.flushSync();
|
|
548
|
+
appendedChunkCount += 1;
|
|
542
549
|
if (onDataAppended !== void 0) {
|
|
543
550
|
const payload = dataAppendedCollector(totalRows);
|
|
544
551
|
if (isOnDataAppendedAsyncCb(onDataAppended)) await onDataAppended(payload);
|
|
545
552
|
else onDataAppended(payload);
|
|
546
553
|
}
|
|
547
|
-
|
|
548
|
-
appender.closeSync();
|
|
549
|
-
if (autoCheckpoint && typeof table.databaseName === "string") {
|
|
550
|
-
const dbManager = new DuckDatabaseManager(this.#conn);
|
|
551
|
-
try {
|
|
554
|
+
if (checkpointChunksFrequency !== void 0 && appendedChunkCount % checkpointChunksFrequency === 0 && typeof table.databaseName === "string") try {
|
|
552
555
|
await dbManager.checkpoint(table.databaseName);
|
|
553
556
|
} catch (e) {
|
|
554
|
-
this.#logger.warning(`Failed to checkpoint database '${table.databaseName}' after appending
|
|
557
|
+
this.#logger.warning(`Failed to checkpoint database '${table.databaseName}' after appending chunk into table '${table.getFullName()}' - ${e?.message ?? ""}`, { table: table.getFullName() });
|
|
555
558
|
}
|
|
556
559
|
}
|
|
560
|
+
appender.closeSync();
|
|
561
|
+
if (autoCheckpoint && typeof table.databaseName === "string") try {
|
|
562
|
+
await dbManager.checkpoint(table.databaseName);
|
|
563
|
+
} catch (e) {
|
|
564
|
+
this.#logger.warning(`Failed to checkpoint database '${table.databaseName}' after appending data into table '${table.getFullName()}' - ${e?.message ?? ""}`, { table: table.getFullName() });
|
|
565
|
+
}
|
|
557
566
|
const timeMs = Math.round(Date.now() - timeStart);
|
|
558
567
|
this.#logger.info(`Successfully appended ${totalRows} rows into '${table.getFullName()}' in ${timeMs}ms`, {
|
|
559
568
|
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,121 +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/create-assert-error.ts
|
|
4
|
-
const createAssertError = (msgOrErrorFactory, fallbackMsg) => {
|
|
5
|
-
if (typeof msgOrErrorFactory === "string" || msgOrErrorFactory === void 0) return new TypeError(msgOrErrorFactory ?? fallbackMsg ?? "Assertion did not pass.");
|
|
6
|
-
return msgOrErrorFactory();
|
|
7
|
-
};
|
|
8
|
-
//#endregion
|
|
9
|
-
//#region src/validation/core/base-validators.ts
|
|
10
|
-
const duckIdentifierNameRegex = /^[a-z_]\w*$/i;
|
|
11
|
-
const duckStorageVersionRegexp = /^v?\d{1,4}\.\d{1,4}\.\d{1,4}$/;
|
|
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
|
-
//#endregion
|
|
117
5
|
//#region src/validation/zod/duck-identifier-zod-schema.ts
|
|
118
|
-
const duckdbReservedKeywordsSet = new Set(duckReservedKeywords.map((k) => k.toUpperCase()));
|
|
119
6
|
/**
|
|
120
7
|
* Check whether a table name identifier is valid
|
|
121
8
|
*/
|
|
@@ -139,25 +26,11 @@ const duckValidatorsZod = {
|
|
|
139
26
|
tableName: duckIdentifierZodSchema
|
|
140
27
|
};
|
|
141
28
|
//#endregion
|
|
142
|
-
//#region src/validation/zod/duck-asserts-zod.ts
|
|
143
|
-
function assertValidAliasName(aliasName) {
|
|
144
|
-
const parsed = z.safeParse(duckValidatorsZod.aliasName, aliasName);
|
|
145
|
-
if (parsed.error) throw createAssertError(`'${aliasName}' is not a valid alias name: ${parsed.error.message}`);
|
|
146
|
-
}
|
|
147
|
-
function assertValidSchemaName(schemaName) {
|
|
148
|
-
const parsed = z.safeParse(duckValidatorsZod.schemaName, schemaName);
|
|
149
|
-
if (parsed.error) throw createAssertError(`'${schemaName}' is not a valid schema name: ${parsed.error.message}`);
|
|
150
|
-
}
|
|
151
|
-
function assertValidTableName(tableName) {
|
|
152
|
-
const parsed = z.safeParse(duckValidatorsZod.tableName, tableName);
|
|
153
|
-
if (parsed.error) throw createAssertError(`'${tableName}' is not a valid table name: ${parsed.error.message}`);
|
|
154
|
-
}
|
|
155
|
-
//#endregion
|
|
156
29
|
//#region src/validation/zod/duck-connection-params-zod-schema.ts
|
|
157
30
|
const duckAllConnectionOptionsZodSchema = z.strictObject({
|
|
158
31
|
accessMode: z.optional(z.enum(["READ_ONLY", "READ_WRITE"])),
|
|
159
32
|
compress: z.optional(z.boolean()),
|
|
160
|
-
type: z.optional(z.enum(
|
|
33
|
+
type: z.optional(z.enum(duckConnectionsOptions.types)),
|
|
161
34
|
blockSize: z.optional(z.int32().min(16384).max(262144)),
|
|
162
35
|
rowGroupSize: z.optional(z.int32().positive()),
|
|
163
36
|
storageVersion: z.optional(z.string().startsWith("v").regex(duckStorageVersionRegexp)),
|
|
@@ -173,35 +46,58 @@ const duckConnectionParamsZodSchema = z.discriminatedUnion("type", [z.strictObje
|
|
|
173
46
|
alias: duckValidatorsZod.aliasName,
|
|
174
47
|
options: z.optional(duckAllConnectionOptionsZodSchema)
|
|
175
48
|
}), z.strictObject({
|
|
176
|
-
type: z.literal("
|
|
177
|
-
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" }),
|
|
178
57
|
alias: duckValidatorsZod.aliasName,
|
|
179
58
|
options: z.optional(duckAllConnectionOptionsZodSchema)
|
|
180
59
|
})]);
|
|
181
60
|
//#endregion
|
|
182
|
-
//#region src/validation/
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const parsed = result.value;
|
|
187
|
-
const { path, ...options } = parsed.params ?? {};
|
|
188
|
-
return duckConnectionParamsZodSchema.parse({
|
|
189
|
-
type: parsed.host,
|
|
190
|
-
alias: parsed.db,
|
|
191
|
-
...path ? { path } : {},
|
|
192
|
-
options: { ...options }
|
|
193
|
-
});
|
|
61
|
+
//#region src/validation/core/create-assert-error.ts
|
|
62
|
+
const createAssertError = (msgOrErrorFactory, fallbackMsg) => {
|
|
63
|
+
if (typeof msgOrErrorFactory === "string" || msgOrErrorFactory === void 0) return new TypeError(msgOrErrorFactory ?? fallbackMsg ?? "Assertion did not pass.");
|
|
64
|
+
return msgOrErrorFactory();
|
|
194
65
|
};
|
|
195
66
|
//#endregion
|
|
196
|
-
//#region src/validation/zod/
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
67
|
+
//#region src/validation/zod/duck-asserts-zod.ts
|
|
68
|
+
function assertValidAliasName(aliasName) {
|
|
69
|
+
const parsed = z.safeParse(duckValidatorsZod.aliasName, aliasName);
|
|
70
|
+
if (parsed.error) throw createAssertError(`'${aliasName}' is not a valid alias name: ${parsed.error.message}`);
|
|
71
|
+
}
|
|
72
|
+
function assertValidSchemaName(schemaName) {
|
|
73
|
+
const parsed = z.safeParse(duckValidatorsZod.schemaName, schemaName);
|
|
74
|
+
if (parsed.error) throw createAssertError(`'${schemaName}' is not a valid schema name: ${parsed.error.message}`);
|
|
75
|
+
}
|
|
76
|
+
function assertValidTableName(tableName) {
|
|
77
|
+
const parsed = z.safeParse(duckValidatorsZod.tableName, tableName);
|
|
78
|
+
if (parsed.error) throw createAssertError(`'${tableName}' is not a valid table name: ${parsed.error.message}`);
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region src/validation/zod/duck-dsn-zod-schema.ts
|
|
82
|
+
const duckDsnZodSchema = z.string().pipe(z.preprocess((dsn, ctx) => {
|
|
83
|
+
const result = parseDsn(dsn);
|
|
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": [
|