@flowblade/sqlduck 0.11.0 → 0.12.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 +38 -30
- package/dist/index.d.mts +23 -79
- package/dist/index.mjs +176 -279
- package/dist/types-DCqYqEsa.d.mts +80 -0
- package/dist/validation/zod/index.d.mts +37 -0
- package/dist/validation/zod/index.mjs +2 -0
- package/dist/zod-CwR_oehs.mjs +207 -0
- package/package.json +18 -21
- package/dist/index.cjs +0 -770
- package/dist/index.d.cts +0 -345
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
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
|
+
//#region src/validation/zod/duck-identifier-zod-schema.ts
|
|
118
|
+
const duckdbReservedKeywordsSet = new Set(duckReservedKeywords.map((k) => k.toUpperCase()));
|
|
119
|
+
/**
|
|
120
|
+
* Check whether a table name identifier is valid
|
|
121
|
+
*/
|
|
122
|
+
const duckIdentifierZodSchema = z.string().min(1).max(120).regex(duckIdentifierNameRegex, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores").refine((value) => !duckdbReservedKeywordsSet.has(value.toUpperCase()), { message: `Identifier value is a DuckDB reserved keyword and cannot be used as an identifier` });
|
|
123
|
+
//#endregion
|
|
124
|
+
//#region src/validation/zod/duck-validators-zod.ts
|
|
125
|
+
/**
|
|
126
|
+
* Common validators for duckdb parameters, tables...
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* import { duckValidatorsZod } from '@flowblade/sqlduck/zod';
|
|
131
|
+
*
|
|
132
|
+
* duckValidatorsZod.tableName.parse('my_table'); // valid
|
|
133
|
+
* duckValidatorsZod.tableName.parse('my table'); // invalid
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
const duckValidatorsZod = {
|
|
137
|
+
aliasName: duckIdentifierZodSchema,
|
|
138
|
+
schemaName: duckIdentifierZodSchema,
|
|
139
|
+
tableName: duckIdentifierZodSchema
|
|
140
|
+
};
|
|
141
|
+
//#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
|
+
//#region src/validation/zod/duck-connection-params-zod-schema.ts
|
|
157
|
+
const duckAllConnectionOptionsZodSchema = z.strictObject({
|
|
158
|
+
accessMode: z.optional(z.enum(["READ_ONLY", "READ_WRITE"])),
|
|
159
|
+
compress: z.optional(z.boolean()),
|
|
160
|
+
type: z.optional(z.enum(["DUCKDB", "SQLITE"])),
|
|
161
|
+
blockSize: z.optional(z.int32().min(16384).max(262144)),
|
|
162
|
+
rowGroupSize: z.optional(z.int32().positive()),
|
|
163
|
+
storageVersion: z.optional(z.string().startsWith("v").regex(duckStorageVersionRegexp)),
|
|
164
|
+
encryptionKey: z.optional(z.string().min(8)),
|
|
165
|
+
encryptionCipher: z.optional(z.enum([
|
|
166
|
+
"CBC",
|
|
167
|
+
"CTR",
|
|
168
|
+
"GCM"
|
|
169
|
+
]))
|
|
170
|
+
});
|
|
171
|
+
const duckConnectionParamsZodSchema = z.discriminatedUnion("type", [z.strictObject({
|
|
172
|
+
type: z.literal("memory"),
|
|
173
|
+
alias: duckValidatorsZod.aliasName,
|
|
174
|
+
options: z.optional(duckAllConnectionOptionsZodSchema)
|
|
175
|
+
}), z.strictObject({
|
|
176
|
+
type: z.literal("duckdb"),
|
|
177
|
+
path: z.string().min(4).endsWith(".db"),
|
|
178
|
+
alias: duckValidatorsZod.aliasName,
|
|
179
|
+
options: z.optional(duckAllConnectionOptionsZodSchema)
|
|
180
|
+
})]);
|
|
181
|
+
//#endregion
|
|
182
|
+
//#region src/validation/zod/parse-duck-dsn-zod.ts
|
|
183
|
+
const parseDuckDSNZod = (dsn) => {
|
|
184
|
+
const result = parseDsn(dsn);
|
|
185
|
+
if (!result.success) throw new Error(`Invalid DuckDB DSN - ${result.message}`);
|
|
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
|
+
});
|
|
194
|
+
};
|
|
195
|
+
//#endregion
|
|
196
|
+
//#region src/validation/zod/is-parsable-duck-dsn-zod.ts
|
|
197
|
+
const isParsableDuckDsnZod = (dsn) => {
|
|
198
|
+
if (typeof dsn !== "string") return false;
|
|
199
|
+
try {
|
|
200
|
+
parseDuckDSNZod(dsn);
|
|
201
|
+
return true;
|
|
202
|
+
} catch {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
//#endregion
|
|
207
|
+
export { assertValidAliasName as a, duckValidatorsZod as c, duckConnectionParamsZodSchema as i, duckReservedKeywords as l, parseDuckDSNZod as n, assertValidSchemaName as o, duckAllConnectionOptionsZodSchema as r, assertValidTableName as s, isParsableDuckDsnZod as t };
|
package/package.json
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowblade/sqlduck",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
"default": "./dist/index.cjs"
|
|
15
|
-
}
|
|
8
|
+
"types": "./dist/index.d.mts",
|
|
9
|
+
"default": "./dist/index.mjs"
|
|
10
|
+
},
|
|
11
|
+
"./zod": {
|
|
12
|
+
"types": "./dist/validation/zod/index.d.mts",
|
|
13
|
+
"default": "./dist/validation/zod/index.mjs"
|
|
16
14
|
},
|
|
17
15
|
"./package.json": "./package.json"
|
|
18
16
|
},
|
|
@@ -58,11 +56,11 @@
|
|
|
58
56
|
"@flowblade/source-duckdb": "^0.20.1",
|
|
59
57
|
"@flowblade/sql-tag": "^0.3.2",
|
|
60
58
|
"@httpx/assert": "^0.16.8",
|
|
59
|
+
"@httpx/dsn-parser": "^1.9.9",
|
|
61
60
|
"@httpx/plain-object": "^2.1.8",
|
|
62
61
|
"@logtape/logtape": "^2.0.5",
|
|
63
62
|
"@standard-schema/spec": "^1.1.0",
|
|
64
63
|
"p-queue": "9.1.0",
|
|
65
|
-
"valibot": "^1.3.1",
|
|
66
64
|
"zod": "^4.3.6"
|
|
67
65
|
},
|
|
68
66
|
"peerDependencies": {
|
|
@@ -70,9 +68,9 @@
|
|
|
70
68
|
},
|
|
71
69
|
"devDependencies": {
|
|
72
70
|
"@belgattitude/eslint-config-bases": "8.10.0",
|
|
73
|
-
"@dotenvx/dotenvx": "1.
|
|
71
|
+
"@dotenvx/dotenvx": "1.59.1",
|
|
74
72
|
"@duckdb/node-api": "1.5.1-r.1",
|
|
75
|
-
"@faker-js/faker": "10.
|
|
73
|
+
"@faker-js/faker": "10.4.0",
|
|
76
74
|
"@flowblade/source-kysely": "^1.3.0",
|
|
77
75
|
"@httpx/assert": "0.16.8",
|
|
78
76
|
"@mitata/counters": "0.0.8",
|
|
@@ -80,13 +78,12 @@
|
|
|
80
78
|
"@size-limit/file": "12.0.1",
|
|
81
79
|
"@testcontainers/mssqlserver": "11.13.0",
|
|
82
80
|
"@total-typescript/ts-reset": "0.6.1",
|
|
83
|
-
"@traversable/zod": "0.0.57",
|
|
84
81
|
"@types/node": "25.5.0",
|
|
85
|
-
"@typescript-eslint/eslint-plugin": "8.
|
|
86
|
-
"@typescript-eslint/parser": "8.
|
|
82
|
+
"@typescript-eslint/eslint-plugin": "8.58.0",
|
|
83
|
+
"@typescript-eslint/parser": "8.58.0",
|
|
87
84
|
"@typescript/native-preview": "7.0.0-dev.20260324.1",
|
|
88
|
-
"@vitest/coverage-v8": "4.1.
|
|
89
|
-
"@vitest/ui": "4.1.
|
|
85
|
+
"@vitest/coverage-v8": "4.1.2",
|
|
86
|
+
"@vitest/ui": "4.1.2",
|
|
90
87
|
"ansis": "4.2.0",
|
|
91
88
|
"browserslist-to-esbuild": "2.1.1",
|
|
92
89
|
"core-js": "3.49.0",
|
|
@@ -97,7 +94,7 @@
|
|
|
97
94
|
"eslint": "8.57.1",
|
|
98
95
|
"execa": "9.6.1",
|
|
99
96
|
"is-in-ci": "2.0.0",
|
|
100
|
-
"kysely": "0.28.
|
|
97
|
+
"kysely": "0.28.15",
|
|
101
98
|
"mitata": "1.0.34",
|
|
102
99
|
"npm-run-all2": "8.0.4",
|
|
103
100
|
"prettier": "3.8.1",
|
|
@@ -105,16 +102,16 @@
|
|
|
105
102
|
"regexp.escape": "2.0.1",
|
|
106
103
|
"rimraf": "6.1.3",
|
|
107
104
|
"size-limit": "12.0.1",
|
|
108
|
-
"sql-formatter": "15.7.
|
|
105
|
+
"sql-formatter": "15.7.3",
|
|
109
106
|
"tarn": "3.0.2",
|
|
110
107
|
"tedious": "19.2.1",
|
|
111
108
|
"testcontainers": "11.13.0",
|
|
112
|
-
"tsdown": "0.21.
|
|
109
|
+
"tsdown": "0.21.7",
|
|
113
110
|
"tsx": "4.21.0",
|
|
114
111
|
"typedoc": "0.28.18",
|
|
115
112
|
"typedoc-plugin-markdown": "4.11.0",
|
|
116
113
|
"typescript": "6.0.2",
|
|
117
|
-
"vitest": "4.1.
|
|
114
|
+
"vitest": "4.1.2"
|
|
118
115
|
},
|
|
119
116
|
"files": [
|
|
120
117
|
"dist"
|