effect-qb 0.16.0 → 0.19.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 +4 -0
- package/dist/index.js +8065 -0
- package/dist/mysql.js +4036 -2418
- package/dist/postgres/metadata.js +2536 -625
- package/dist/postgres.js +8248 -7857
- package/dist/sqlite.js +8854 -0
- package/dist/standard.js +8019 -0
- package/package.json +15 -3
- package/src/casing.ts +71 -0
- package/src/index.ts +2 -0
- package/src/internal/casing.ts +89 -0
- package/src/internal/column-state.ts +11 -6
- package/src/internal/column.ts +44 -7
- package/src/internal/datatypes/define.ts +2 -1
- package/src/internal/datatypes/enrich.ts +23 -0
- package/src/internal/datatypes/lookup.ts +14 -7
- package/src/internal/derived-table.ts +7 -13
- package/src/internal/dialect-renderers/mysql.ts +2046 -0
- package/src/{postgres/internal/sql-expression-renderer.ts → internal/dialect-renderers/postgres.ts} +867 -283
- package/src/{mysql/internal/sql-expression-renderer.ts → internal/dialect-renderers/sqlite.ts} +834 -358
- package/src/internal/dialect.ts +37 -0
- package/src/internal/dsl-mutation-runtime.ts +29 -10
- package/src/internal/dsl-plan-runtime.ts +41 -24
- package/src/internal/dsl-query-runtime.ts +11 -31
- package/src/internal/dsl-transaction-ddl-runtime.ts +61 -15
- package/src/internal/executor.ts +57 -15
- package/src/internal/expression-ast.ts +3 -2
- package/src/internal/grouping-key.ts +216 -9
- package/src/internal/implication-runtime.ts +3 -2
- package/src/internal/json/types.ts +155 -40
- package/src/internal/predicate/context.ts +14 -1
- package/src/internal/predicate/key.ts +19 -2
- package/src/internal/predicate/runtime.ts +30 -3
- package/src/internal/query.d.ts +38 -11
- package/src/internal/query.ts +315 -54
- package/src/internal/renderer.ts +51 -6
- package/src/internal/runtime/driver-value-mapping.ts +58 -0
- package/src/internal/runtime/normalize.ts +74 -43
- package/src/internal/runtime/schema.ts +5 -3
- package/src/internal/runtime/value.ts +153 -30
- package/src/internal/scalar.ts +6 -1
- package/src/internal/schema-derivation.d.ts +12 -61
- package/src/internal/schema-derivation.ts +90 -38
- package/src/internal/schema-expression.ts +2 -2
- package/src/internal/sql-expression-renderer.ts +19 -0
- package/src/internal/standard-dsl.ts +6885 -0
- package/src/internal/table-options.ts +229 -62
- package/src/internal/table.d.ts +33 -32
- package/src/internal/table.ts +469 -160
- package/src/mysql/column-extension.ts +3 -0
- package/src/mysql/column.ts +27 -12
- package/src/mysql/datatypes/index.ts +24 -2
- package/src/mysql/errors/catalog.ts +5 -5
- package/src/mysql/errors/normalize.ts +2 -2
- package/src/mysql/executor.ts +7 -5
- package/src/mysql/internal/dialect.ts +9 -4
- package/src/mysql/internal/dsl.ts +906 -324
- package/src/mysql/internal/renderer.ts +7 -2
- package/src/mysql/json.ts +37 -0
- package/src/mysql/query-extension.ts +16 -0
- package/src/mysql/query.ts +9 -2
- package/src/mysql/renderer.ts +31 -4
- package/src/mysql.ts +4 -12
- package/src/postgres/column-extension.ts +28 -0
- package/src/postgres/column.ts +9 -13
- package/src/postgres/datatypes/index.d.ts +2 -1
- package/src/postgres/datatypes/index.ts +3 -2
- package/src/postgres/errors/normalize.ts +2 -2
- package/src/postgres/executor.ts +55 -10
- package/src/postgres/function/core.ts +20 -4
- package/src/postgres/function/index.ts +1 -17
- package/src/postgres/internal/dialect.ts +9 -4
- package/src/postgres/internal/dsl.ts +850 -359
- package/src/postgres/internal/renderer.ts +7 -2
- package/src/postgres/internal/schema-ddl.ts +22 -9
- package/src/postgres/internal/schema-model.ts +244 -10
- package/src/postgres/json.ts +100 -24
- package/src/postgres/jsonb.ts +38 -0
- package/src/postgres/query-extension.ts +2 -0
- package/src/postgres/query.ts +9 -2
- package/src/postgres/renderer.ts +31 -4
- package/src/postgres/schema-management.ts +108 -16
- package/src/postgres/schema.ts +98 -15
- package/src/postgres/table.ts +203 -398
- package/src/postgres/type.ts +8 -7
- package/src/postgres.ts +9 -11
- package/src/sqlite/column-extension.ts +3 -0
- package/src/sqlite/column.ts +127 -0
- package/src/sqlite/datatypes/index.ts +80 -0
- package/src/sqlite/datatypes/spec.ts +98 -0
- package/src/sqlite/errors/catalog.ts +103 -0
- package/src/sqlite/errors/fields.ts +19 -0
- package/src/sqlite/errors/index.ts +19 -0
- package/src/sqlite/errors/normalize.ts +229 -0
- package/src/sqlite/errors/requirements.ts +71 -0
- package/src/sqlite/errors/types.ts +29 -0
- package/src/sqlite/executor.ts +229 -0
- package/src/sqlite/function/aggregate.ts +2 -0
- package/src/sqlite/function/core.ts +2 -0
- package/src/sqlite/function/index.ts +19 -0
- package/src/sqlite/function/string.ts +2 -0
- package/src/sqlite/function/temporal.ts +100 -0
- package/src/sqlite/function/window.ts +2 -0
- package/src/sqlite/internal/dialect.ts +42 -0
- package/src/sqlite/internal/dsl.ts +6979 -0
- package/src/sqlite/internal/renderer.ts +51 -0
- package/src/sqlite/json.ts +39 -0
- package/src/sqlite/query-extension.ts +2 -0
- package/src/sqlite/query.ts +196 -0
- package/src/sqlite/renderer.ts +51 -0
- package/src/sqlite.ts +14 -0
- package/src/standard/column.ts +163 -0
- package/src/standard/datatypes/index.ts +83 -0
- package/src/standard/datatypes/spec.ts +98 -0
- package/src/standard/dialect.ts +40 -0
- package/src/standard/function/aggregate.ts +2 -0
- package/src/standard/function/core.ts +2 -0
- package/src/standard/function/index.ts +18 -0
- package/src/standard/function/string.ts +2 -0
- package/src/standard/function/temporal.ts +78 -0
- package/src/standard/function/window.ts +2 -0
- package/src/standard/internal/renderer.ts +45 -0
- package/src/standard/query.ts +152 -0
- package/src/standard/renderer.ts +21 -0
- package/src/standard/table.ts +147 -0
- package/src/standard.ts +18 -0
- package/src/internal/aggregation-validation.ts +0 -57
- package/src/mysql/table.ts +0 -157
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import type * as Renderer from "../../internal/renderer.js"
|
|
2
|
+
import {
|
|
3
|
+
findSqliteErrorDescriptorsByNumberLoose,
|
|
4
|
+
getSqliteErrorDescriptor,
|
|
5
|
+
isSqliteErrorNumber,
|
|
6
|
+
isSqliteErrorSymbol,
|
|
7
|
+
type SqliteErrorDescriptor,
|
|
8
|
+
type SqliteErrorNumber,
|
|
9
|
+
type SqliteErrorSymbol,
|
|
10
|
+
} from "./catalog.js"
|
|
11
|
+
import type {
|
|
12
|
+
SqliteErrorFields,
|
|
13
|
+
SqliteQueryContext
|
|
14
|
+
} from "./fields.js"
|
|
15
|
+
import type {
|
|
16
|
+
SqliteErrorLike,
|
|
17
|
+
SqliteKnownErrorBase
|
|
18
|
+
} from "./types.js"
|
|
19
|
+
|
|
20
|
+
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
21
|
+
typeof value === "object" && value !== null
|
|
22
|
+
|
|
23
|
+
const unwrapSqliteDriverCause = (cause: unknown): unknown => {
|
|
24
|
+
let current = cause
|
|
25
|
+
while (
|
|
26
|
+
isRecord(current) &&
|
|
27
|
+
"_tag" in current &&
|
|
28
|
+
current._tag === "SqlError" &&
|
|
29
|
+
"cause" in current
|
|
30
|
+
) {
|
|
31
|
+
current = current.cause
|
|
32
|
+
}
|
|
33
|
+
return current
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const asString = (value: unknown): string | undefined =>
|
|
37
|
+
typeof value === "string" ? value : undefined
|
|
38
|
+
|
|
39
|
+
const asBoolean = (value: unknown): boolean | undefined =>
|
|
40
|
+
typeof value === "boolean" ? value : undefined
|
|
41
|
+
|
|
42
|
+
const asNumber = (value: unknown): number | undefined => {
|
|
43
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
44
|
+
return value
|
|
45
|
+
}
|
|
46
|
+
if (typeof value === "string" && /^[+-]?\d+$/.test(value.trim())) {
|
|
47
|
+
const parsed = Number(value.trim())
|
|
48
|
+
return Number.isFinite(parsed) ? parsed : undefined
|
|
49
|
+
}
|
|
50
|
+
return undefined
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const normalizeFields = (error: Record<string, unknown>): SqliteErrorFields => ({
|
|
54
|
+
code: asString(error.code),
|
|
55
|
+
errno: asNumber(error.errno),
|
|
56
|
+
sqlState: asString(error.sqlState),
|
|
57
|
+
sqlMessage: asString(error.sqlMessage),
|
|
58
|
+
fatal: asBoolean(error.fatal),
|
|
59
|
+
sql: asString(error.sql),
|
|
60
|
+
syscall: asString(error.syscall),
|
|
61
|
+
address: asString(error.address),
|
|
62
|
+
port: asNumber(error.port),
|
|
63
|
+
hostname: asString(error.hostname)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
export type { SqliteErrorLike } from "./types.js"
|
|
67
|
+
|
|
68
|
+
/** Structured known SQLite error derived from the SQLite result-code catalog. */
|
|
69
|
+
export type KnownSqliteError<Symbol extends SqliteErrorSymbol = SqliteErrorSymbol> =
|
|
70
|
+
SqliteKnownErrorBase & { readonly symbol: Symbol }
|
|
71
|
+
|
|
72
|
+
/** Extracts the normalized SQLite error variant for a specific symbol. */
|
|
73
|
+
export type KnownSqliteErrorBySymbol<Symbol extends SqliteErrorSymbol> = KnownSqliteError<Symbol>
|
|
74
|
+
|
|
75
|
+
/** SQLite-like error whose symbol or number is not in the current catalog. */
|
|
76
|
+
export type UnknownSqliteCodeError = Readonly<{
|
|
77
|
+
readonly _tag: "@sqlite/unknown/code"
|
|
78
|
+
readonly code?: string
|
|
79
|
+
readonly errno?: string | number
|
|
80
|
+
readonly message: string
|
|
81
|
+
readonly query?: SqliteQueryContext
|
|
82
|
+
readonly raw: SqliteErrorLike
|
|
83
|
+
} & SqliteErrorFields>
|
|
84
|
+
|
|
85
|
+
/** Fallback for non-SQLite driver failures in the SQLite executor path. */
|
|
86
|
+
export type UnknownSqliteDriverError = Readonly<{
|
|
87
|
+
readonly _tag: "@sqlite/unknown/driver"
|
|
88
|
+
readonly message: string
|
|
89
|
+
readonly query?: SqliteQueryContext
|
|
90
|
+
readonly cause: unknown
|
|
91
|
+
}>
|
|
92
|
+
|
|
93
|
+
/** Any SQLite-specific driver failure surfaced by the SQLite executor. */
|
|
94
|
+
export type SqliteDriverError =
|
|
95
|
+
| KnownSqliteError
|
|
96
|
+
| UnknownSqliteCodeError
|
|
97
|
+
| UnknownSqliteDriverError
|
|
98
|
+
|
|
99
|
+
/** Runtime guard for objects that look like SQLite driver errors. */
|
|
100
|
+
export const isSqliteErrorLike = (value: unknown): value is SqliteErrorLike =>
|
|
101
|
+
isRecord(value) &&
|
|
102
|
+
(
|
|
103
|
+
typeof value.code === "string" ||
|
|
104
|
+
typeof value.errno === "string" ||
|
|
105
|
+
typeof value.errno === "number" ||
|
|
106
|
+
typeof value.sqlState === "string" ||
|
|
107
|
+
typeof value.sqlMessage === "string" ||
|
|
108
|
+
typeof value.message === "string" ||
|
|
109
|
+
typeof value.fatal === "boolean"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
const errorMessageOf = (error: SqliteErrorLike): string =>
|
|
113
|
+
error.sqlMessage ?? error.message ?? "SQLite driver error"
|
|
114
|
+
|
|
115
|
+
const numberOf = (error: SqliteErrorLike): string | undefined => {
|
|
116
|
+
if (typeof error.errno === "number" && Number.isFinite(error.errno)) {
|
|
117
|
+
return String(error.errno)
|
|
118
|
+
}
|
|
119
|
+
if (typeof error.errno === "string" && error.errno.trim() !== "") {
|
|
120
|
+
return error.errno
|
|
121
|
+
}
|
|
122
|
+
return undefined
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const findDescriptor = (error: SqliteErrorLike): SqliteErrorDescriptor | undefined => {
|
|
126
|
+
if (typeof error.code === "string" && isSqliteErrorSymbol(error.code)) {
|
|
127
|
+
return getSqliteErrorDescriptor(error.code)
|
|
128
|
+
}
|
|
129
|
+
if (typeof error.code === "string" && isSqliteErrorNumber(error.code)) {
|
|
130
|
+
const matches = findSqliteErrorDescriptorsByNumberLoose(error.code)
|
|
131
|
+
if (matches?.length === 1) {
|
|
132
|
+
return matches[0]
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const number = numberOf(error)
|
|
136
|
+
if (number !== undefined) {
|
|
137
|
+
const matches = findSqliteErrorDescriptorsByNumberLoose(number)
|
|
138
|
+
if (!matches || matches.length === 0) {
|
|
139
|
+
return undefined
|
|
140
|
+
}
|
|
141
|
+
if (matches.length === 1) {
|
|
142
|
+
return matches[0]
|
|
143
|
+
}
|
|
144
|
+
if (typeof error.code === "string") {
|
|
145
|
+
return matches.find((descriptor) => descriptor.symbol === error.code)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return undefined
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const makeKnownSqliteError = (
|
|
152
|
+
descriptor: SqliteErrorDescriptor,
|
|
153
|
+
raw: SqliteErrorLike,
|
|
154
|
+
query?: SqliteQueryContext
|
|
155
|
+
): SqliteKnownErrorBase => {
|
|
156
|
+
const fields = normalizeFields(raw as Record<string, unknown>)
|
|
157
|
+
return {
|
|
158
|
+
_tag: descriptor.tag,
|
|
159
|
+
category: descriptor.category,
|
|
160
|
+
number: descriptor.number,
|
|
161
|
+
symbol: descriptor.symbol,
|
|
162
|
+
messageTemplate: descriptor.messageTemplate,
|
|
163
|
+
message: errorMessageOf(raw),
|
|
164
|
+
query,
|
|
165
|
+
raw,
|
|
166
|
+
...fields
|
|
167
|
+
} as SqliteKnownErrorBase
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** Normalizes an unknown failure into a structured SQLite driver error. */
|
|
171
|
+
export const normalizeSqliteDriverError = (
|
|
172
|
+
cause: unknown,
|
|
173
|
+
query?: SqliteQueryContext | Renderer.RenderedQuery<any, "sqlite">
|
|
174
|
+
): SqliteDriverError => {
|
|
175
|
+
const normalizedCause = unwrapSqliteDriverCause(cause)
|
|
176
|
+
const context = query === undefined
|
|
177
|
+
? undefined
|
|
178
|
+
: "sql" in query
|
|
179
|
+
? { sql: query.sql, params: query.params }
|
|
180
|
+
: query
|
|
181
|
+
|
|
182
|
+
if (!isSqliteErrorLike(normalizedCause)) {
|
|
183
|
+
return {
|
|
184
|
+
_tag: "@sqlite/unknown/driver",
|
|
185
|
+
message: normalizedCause instanceof Error ? normalizedCause.message : "Unknown SQLite driver failure",
|
|
186
|
+
query: context,
|
|
187
|
+
cause
|
|
188
|
+
} as UnknownSqliteDriverError
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const descriptor = findDescriptor(normalizedCause)
|
|
192
|
+
if (descriptor !== undefined) {
|
|
193
|
+
return makeKnownSqliteError(descriptor, normalizedCause, context)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (typeof normalizedCause.code === "string" || numberOf(normalizedCause) !== undefined) {
|
|
197
|
+
return {
|
|
198
|
+
_tag: "@sqlite/unknown/code",
|
|
199
|
+
code: asString(normalizedCause.code),
|
|
200
|
+
errno: normalizedCause.errno,
|
|
201
|
+
message: errorMessageOf(normalizedCause),
|
|
202
|
+
query: context,
|
|
203
|
+
raw: normalizedCause,
|
|
204
|
+
...normalizeFields(normalizedCause as Record<string, unknown>)
|
|
205
|
+
} as UnknownSqliteCodeError
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
_tag: "@sqlite/unknown/driver",
|
|
210
|
+
message: errorMessageOf(normalizedCause),
|
|
211
|
+
query: context,
|
|
212
|
+
cause
|
|
213
|
+
} as UnknownSqliteDriverError
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** Type guard for a specific SQLite catalog symbol. */
|
|
217
|
+
export const hasSymbol = <Symbol extends SqliteErrorSymbol>(
|
|
218
|
+
error: SqliteDriverError | { readonly symbol?: string },
|
|
219
|
+
symbol: Symbol
|
|
220
|
+
): error is KnownSqliteErrorBySymbol<Symbol> =>
|
|
221
|
+
"symbol" in error && error.symbol === symbol
|
|
222
|
+
|
|
223
|
+
/** Type guard for a specific documented SQLite error number. */
|
|
224
|
+
export const hasNumber = <Number extends SqliteErrorNumber>(
|
|
225
|
+
error: SqliteDriverError | { readonly number?: string; readonly errno?: string | number },
|
|
226
|
+
number: Number
|
|
227
|
+
): error is KnownSqliteError & { readonly number: Number } =>
|
|
228
|
+
("number" in error && error.number === number) ||
|
|
229
|
+
("errno" in error && String(error.errno) === number)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { read_query_capabilities, type QueryCapability, type QueryRequirement } from "../../internal/query-requirements.js"
|
|
2
|
+
import type { SqliteQueryContext } from "./fields.js"
|
|
3
|
+
import type {
|
|
4
|
+
KnownSqliteError,
|
|
5
|
+
SqliteDriverError,
|
|
6
|
+
UnknownSqliteCodeError,
|
|
7
|
+
UnknownSqliteDriverError
|
|
8
|
+
} from "./normalize.js"
|
|
9
|
+
|
|
10
|
+
export type SqliteQueryRequirement = Extract<QueryRequirement, "write" | "ddl" | "transaction" | "locking">
|
|
11
|
+
|
|
12
|
+
export const sqlite_requirements_by_sqlstate_prefix = {
|
|
13
|
+
"23": ["write"]
|
|
14
|
+
} as const satisfies Partial<Record<string, readonly SqliteQueryRequirement[]>>
|
|
15
|
+
|
|
16
|
+
export type SqliteQueryRequirementsError = Readonly<{
|
|
17
|
+
readonly _tag: "@sqlite/unknown/query-requirements"
|
|
18
|
+
readonly message: string
|
|
19
|
+
readonly query?: SqliteQueryContext
|
|
20
|
+
readonly requiredCapabilities: readonly SqliteQueryRequirement[]
|
|
21
|
+
readonly actualCapabilities: readonly QueryCapability[]
|
|
22
|
+
readonly cause: SqliteDriverError
|
|
23
|
+
}>
|
|
24
|
+
|
|
25
|
+
export type SqliteReadQueryError =
|
|
26
|
+
| KnownSqliteError
|
|
27
|
+
| UnknownSqliteCodeError
|
|
28
|
+
| UnknownSqliteDriverError
|
|
29
|
+
| SqliteQueryRequirementsError
|
|
30
|
+
|
|
31
|
+
const requiresWriteSqliteError = (error: SqliteDriverError): boolean =>
|
|
32
|
+
requirements_of_sqlite_error(error).length > 0
|
|
33
|
+
|
|
34
|
+
const lookup_sqlite_requirements = (
|
|
35
|
+
sqlState: string
|
|
36
|
+
): readonly SqliteQueryRequirement[] => {
|
|
37
|
+
const prefix = sqlState.slice(0, 2)
|
|
38
|
+
return prefix in sqlite_requirements_by_sqlstate_prefix
|
|
39
|
+
? sqlite_requirements_by_sqlstate_prefix[prefix as keyof typeof sqlite_requirements_by_sqlstate_prefix]
|
|
40
|
+
: []
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const requirements_of_sqlite_error = (
|
|
44
|
+
error: SqliteDriverError
|
|
45
|
+
): readonly SqliteQueryRequirement[] => {
|
|
46
|
+
if ("sqlState" in error && typeof error.sqlState === "string") {
|
|
47
|
+
return lookup_sqlite_requirements(error.sqlState)
|
|
48
|
+
}
|
|
49
|
+
if ("symbol" in error && (error.symbol === "SQLITE_READONLY" || error.symbol.startsWith("SQLITE_CONSTRAINT"))) {
|
|
50
|
+
return ["write"]
|
|
51
|
+
}
|
|
52
|
+
return []
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const narrowSqliteDriverErrorForReadQuery = (
|
|
56
|
+
error: SqliteDriverError
|
|
57
|
+
): SqliteReadQueryError => {
|
|
58
|
+
const requiredCapabilities = requirements_of_sqlite_error(error)
|
|
59
|
+
if (!requiresWriteSqliteError(error)) {
|
|
60
|
+
return error as SqliteReadQueryError
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
_tag: "@sqlite/unknown/query-requirements",
|
|
65
|
+
message: "SQLite driver error requires query capabilities not provided by this plan",
|
|
66
|
+
query: error.query,
|
|
67
|
+
requiredCapabilities,
|
|
68
|
+
actualCapabilities: read_query_capabilities,
|
|
69
|
+
cause: error
|
|
70
|
+
} satisfies SqliteQueryRequirementsError
|
|
71
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { SqliteErrorNumber, SqliteErrorSymbol, SqliteErrorTag } from "./catalog.js"
|
|
2
|
+
import type { SqliteErrorFields, SqliteQueryContext } from "./fields.js"
|
|
3
|
+
|
|
4
|
+
/** Raw SQLite-like error shape as commonly exposed by client libraries. */
|
|
5
|
+
export interface SqliteErrorLike {
|
|
6
|
+
readonly code?: string
|
|
7
|
+
readonly errno?: string | number
|
|
8
|
+
readonly sqlState?: string
|
|
9
|
+
readonly sqlMessage?: string
|
|
10
|
+
readonly message?: string
|
|
11
|
+
readonly fatal?: boolean
|
|
12
|
+
readonly sql?: string
|
|
13
|
+
readonly syscall?: string
|
|
14
|
+
readonly address?: string
|
|
15
|
+
readonly port?: string | number
|
|
16
|
+
readonly hostname?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Broad known-SQLite error surface used by the normalizer return type. */
|
|
20
|
+
export interface SqliteKnownErrorBase extends SqliteErrorFields {
|
|
21
|
+
readonly _tag: SqliteErrorTag
|
|
22
|
+
readonly category: "sqlite"
|
|
23
|
+
readonly number: SqliteErrorNumber
|
|
24
|
+
readonly symbol: SqliteErrorSymbol
|
|
25
|
+
readonly messageTemplate: string
|
|
26
|
+
readonly message: string
|
|
27
|
+
readonly query?: SqliteQueryContext
|
|
28
|
+
readonly raw: SqliteErrorLike
|
|
29
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect"
|
|
2
|
+
import * as SqlClient from "@effect/sql/SqlClient"
|
|
3
|
+
import * as Stream from "effect/Stream"
|
|
4
|
+
|
|
5
|
+
import * as CoreExecutor from "../internal/executor.js"
|
|
6
|
+
import * as CoreQuery from "../internal/query.js"
|
|
7
|
+
import * as CoreRenderer from "../internal/renderer.js"
|
|
8
|
+
import type * as Expression from "../internal/scalar.js"
|
|
9
|
+
import type { SqliteDatatypeFamily, SqliteDatatypeKind } from "./datatypes/spec.js"
|
|
10
|
+
import { renderSqlitePlan } from "./internal/renderer.js"
|
|
11
|
+
import {
|
|
12
|
+
narrowSqliteDriverErrorForReadQuery,
|
|
13
|
+
normalizeSqliteDriverError,
|
|
14
|
+
type SqliteDriverError,
|
|
15
|
+
type SqliteReadQueryError
|
|
16
|
+
} from "./errors/index.js"
|
|
17
|
+
|
|
18
|
+
/** SQLite-specialized flat row returned by SQL drivers. */
|
|
19
|
+
export type FlatRow = CoreExecutor.FlatRow
|
|
20
|
+
/** Runtime decode failure raised after SQL execution but before row remapping. */
|
|
21
|
+
export type RowDecodeError = CoreExecutor.RowDecodeError
|
|
22
|
+
/** SQLite-specialized rendered-query driver. */
|
|
23
|
+
export type Driver<Error = never, Context = never> = CoreExecutor.Driver<"sqlite", Error, Context>
|
|
24
|
+
/** SQLite-specialized executor contract. */
|
|
25
|
+
export type Executor<Error = never, Context = never> = CoreExecutor.Executor<"sqlite", Error, Context>
|
|
26
|
+
/** SQLite-specialized renderer contract. */
|
|
27
|
+
export type Renderer = CoreRenderer.Renderer<"sqlite">
|
|
28
|
+
export type ValueMappings = Expression.DriverValueMappingsFor<SqliteDatatypeKind | "uuid", SqliteDatatypeFamily | "uuid">
|
|
29
|
+
/** Optional renderer / driver overrides for the standard SQLite executor pipeline. */
|
|
30
|
+
export interface MakeOptions<Error = never, Context = never> {
|
|
31
|
+
readonly renderer?: Renderer
|
|
32
|
+
readonly driver?: Driver<Error, Context>
|
|
33
|
+
readonly driverMode?: CoreExecutor.DriverMode
|
|
34
|
+
readonly valueMappings?: ValueMappings
|
|
35
|
+
}
|
|
36
|
+
/** Standard composed error shape for SQLite executors. */
|
|
37
|
+
export type SqliteExecutorError = SqliteDriverError | RowDecodeError
|
|
38
|
+
/** Read-query error surface emitted by built-in SQLite executors. */
|
|
39
|
+
export type SqliteQueryError<PlanValue extends CoreQuery.QueryPlan<any, any, any, any, any, any, any, any, any, any>> =
|
|
40
|
+
Exclude<CoreQuery.CapabilitiesOfPlan<PlanValue>, "read"> extends never ? SqliteReadQueryError : SqliteExecutorError
|
|
41
|
+
|
|
42
|
+
/** Runs an effect within the ambient SQLite SQL transaction service. */
|
|
43
|
+
export const withTransaction = CoreExecutor.withTransaction
|
|
44
|
+
/** Runs an effect in a nested SQLite SQL transaction scope. */
|
|
45
|
+
export const withSavepoint = CoreExecutor.withSavepoint
|
|
46
|
+
|
|
47
|
+
/** SQLite executor whose error channel narrows based on the query plan. */
|
|
48
|
+
export interface QueryExecutor<Context = never> {
|
|
49
|
+
readonly dialect: "sqlite"
|
|
50
|
+
execute<PlanValue extends CoreQuery.QueryPlan<any, any, any, any, any, any, any, any, any, any>>(
|
|
51
|
+
plan: CoreQuery.DialectCompatiblePlan<PlanValue, "sqlite">
|
|
52
|
+
): Effect.Effect<CoreQuery.ResultRows<PlanValue>, SqliteQueryError<PlanValue>, Context>
|
|
53
|
+
stream<PlanValue extends CoreQuery.QueryPlan<any, any, any, any, any, any, any, any, any, any>>(
|
|
54
|
+
plan: Exclude<CoreQuery.CapabilitiesOfPlan<PlanValue>, "read" | "locking"> extends never
|
|
55
|
+
? CoreQuery.DialectCompatiblePlan<PlanValue, "sqlite">
|
|
56
|
+
: never
|
|
57
|
+
): Stream.Stream<CoreQuery.ResultRow<PlanValue>, SqliteQueryError<PlanValue>, Context>
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
type DriverExecute<Error, Context> = <Row>(
|
|
61
|
+
query: CoreRenderer.RenderedQuery<Row, "sqlite">
|
|
62
|
+
) => Effect.Effect<ReadonlyArray<FlatRow>, Error, Context>
|
|
63
|
+
|
|
64
|
+
type DriverHandlers<Error, Context> = {
|
|
65
|
+
readonly execute: DriverExecute<Error, Context>
|
|
66
|
+
readonly stream: <Row>(
|
|
67
|
+
query: CoreRenderer.RenderedQuery<Row, "sqlite">
|
|
68
|
+
) => Stream.Stream<FlatRow, Error, Context>
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Constructs a SQLite-specialized SQL driver. */
|
|
72
|
+
export function driver<
|
|
73
|
+
Error = never,
|
|
74
|
+
Context = never
|
|
75
|
+
>(
|
|
76
|
+
execute: DriverExecute<Error, Context>
|
|
77
|
+
): Driver<Error, Context>
|
|
78
|
+
export function driver<
|
|
79
|
+
Error = never,
|
|
80
|
+
Context = never
|
|
81
|
+
>(
|
|
82
|
+
handlers: DriverHandlers<Error, Context>
|
|
83
|
+
): Driver<Error, Context>
|
|
84
|
+
export function driver<
|
|
85
|
+
Error = never,
|
|
86
|
+
Context = never
|
|
87
|
+
>(
|
|
88
|
+
dialect: "sqlite",
|
|
89
|
+
execute: DriverExecute<Error, Context>
|
|
90
|
+
): Driver<Error, Context>
|
|
91
|
+
export function driver<
|
|
92
|
+
Error = never,
|
|
93
|
+
Context = never
|
|
94
|
+
>(
|
|
95
|
+
dialect: "sqlite",
|
|
96
|
+
handlers: DriverHandlers<Error, Context>
|
|
97
|
+
): Driver<Error, Context>
|
|
98
|
+
export function driver<
|
|
99
|
+
Error = never,
|
|
100
|
+
Context = never
|
|
101
|
+
>(
|
|
102
|
+
dialectOrExecute: "sqlite" | DriverExecute<Error, Context> | DriverHandlers<Error, Context>,
|
|
103
|
+
maybeExecute?: DriverExecute<Error, Context> | DriverHandlers<Error, Context>
|
|
104
|
+
): Driver<Error, Context> {
|
|
105
|
+
const executeOrHandlers = typeof dialectOrExecute === "string" ? maybeExecute : dialectOrExecute
|
|
106
|
+
return typeof executeOrHandlers === "function"
|
|
107
|
+
? CoreExecutor.driver("sqlite", executeOrHandlers)
|
|
108
|
+
: CoreExecutor.driver("sqlite", executeOrHandlers as DriverHandlers<Error, Context>)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const fromDriver = <
|
|
112
|
+
Error = never,
|
|
113
|
+
Context = never
|
|
114
|
+
>(
|
|
115
|
+
renderer: Renderer,
|
|
116
|
+
sqlDriver: Driver<Error, Context>,
|
|
117
|
+
driverMode: CoreExecutor.DriverMode = "raw",
|
|
118
|
+
valueMappings?: Expression.DriverValueMappings
|
|
119
|
+
): QueryExecutor<Context> => ({
|
|
120
|
+
dialect: "sqlite",
|
|
121
|
+
execute(plan) {
|
|
122
|
+
const rendered = renderer.render(plan)
|
|
123
|
+
return Effect.mapError(
|
|
124
|
+
Effect.flatMap(
|
|
125
|
+
sqlDriver.execute(rendered),
|
|
126
|
+
(rows) => Effect.try({
|
|
127
|
+
try: () => CoreExecutor.decodeRows(rendered, plan, rows, { driverMode, valueMappings }),
|
|
128
|
+
catch: (error) => error as RowDecodeError
|
|
129
|
+
})
|
|
130
|
+
),
|
|
131
|
+
(error) => {
|
|
132
|
+
if (typeof error === "object" && error !== null && "_tag" in error && error._tag === "RowDecodeError") {
|
|
133
|
+
return error as RowDecodeError
|
|
134
|
+
}
|
|
135
|
+
const normalized = normalizeSqliteDriverError(error, rendered)
|
|
136
|
+
return CoreExecutor.hasWriteCapability(plan)
|
|
137
|
+
? normalized
|
|
138
|
+
: narrowSqliteDriverErrorForReadQuery(normalized)
|
|
139
|
+
}
|
|
140
|
+
) as Effect.Effect<any, any, Context>
|
|
141
|
+
},
|
|
142
|
+
stream(plan) {
|
|
143
|
+
const rendered = renderer.render(plan)
|
|
144
|
+
return Stream.mapError(
|
|
145
|
+
Stream.mapChunksEffect(
|
|
146
|
+
sqlDriver.stream(rendered),
|
|
147
|
+
(rows) => Effect.try({
|
|
148
|
+
try: () => CoreExecutor.decodeChunk(rendered, plan, rows, { driverMode, valueMappings }),
|
|
149
|
+
catch: (error) => error as RowDecodeError
|
|
150
|
+
})
|
|
151
|
+
),
|
|
152
|
+
(error) => {
|
|
153
|
+
if (typeof error === "object" && error !== null && "_tag" in error && error._tag === "RowDecodeError") {
|
|
154
|
+
return error as RowDecodeError
|
|
155
|
+
}
|
|
156
|
+
const normalized = normalizeSqliteDriverError(error, rendered)
|
|
157
|
+
return CoreExecutor.hasWriteCapability(plan)
|
|
158
|
+
? normalized
|
|
159
|
+
: narrowSqliteDriverErrorForReadQuery(normalized)
|
|
160
|
+
}
|
|
161
|
+
) as Stream.Stream<any, any, Context>
|
|
162
|
+
}
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
const sqlClientDriver = (): Driver<any, SqlClient.SqlClient> =>
|
|
166
|
+
driver({
|
|
167
|
+
execute: (query: CoreRenderer.RenderedQuery<any, "sqlite">) =>
|
|
168
|
+
Effect.flatMap(SqlClient.SqlClient, (sql) =>
|
|
169
|
+
sql.unsafe<FlatRow>(query.sql, [...query.params])),
|
|
170
|
+
stream: (query: CoreRenderer.RenderedQuery<any, "sqlite">) =>
|
|
171
|
+
Stream.unwrap(
|
|
172
|
+
Effect.map(
|
|
173
|
+
Effect.flatMap(SqlClient.SqlClient, (sql) =>
|
|
174
|
+
sql.unsafe<FlatRow>(query.sql, [...query.params])),
|
|
175
|
+
(rows) => Stream.fromIterable(rows)
|
|
176
|
+
)
|
|
177
|
+
)
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Creates the standard SQLite executor pipeline.
|
|
182
|
+
*
|
|
183
|
+
* By default this uses the built-in SQLite renderer plus the ambient
|
|
184
|
+
* `@effect/sql` `SqlClient`. Advanced callers can override the renderer,
|
|
185
|
+
* driver, or both.
|
|
186
|
+
*/
|
|
187
|
+
export function make(): QueryExecutor<SqlClient.SqlClient>
|
|
188
|
+
export function make(options: {
|
|
189
|
+
readonly renderer?: Renderer
|
|
190
|
+
readonly driverMode?: CoreExecutor.DriverMode
|
|
191
|
+
readonly valueMappings?: ValueMappings
|
|
192
|
+
}): QueryExecutor<SqlClient.SqlClient>
|
|
193
|
+
export function make<Error = never, Context = never>(
|
|
194
|
+
options: {
|
|
195
|
+
readonly renderer?: Renderer
|
|
196
|
+
readonly driver: Driver<Error, Context>
|
|
197
|
+
readonly driverMode?: CoreExecutor.DriverMode
|
|
198
|
+
readonly valueMappings?: ValueMappings
|
|
199
|
+
}
|
|
200
|
+
): QueryExecutor<Context>
|
|
201
|
+
export function make<Error = never, Context = never>(
|
|
202
|
+
options: MakeOptions<Error, Context> = {}
|
|
203
|
+
): QueryExecutor<any> {
|
|
204
|
+
if (options.driver) {
|
|
205
|
+
return fromDriver(
|
|
206
|
+
options.renderer ?? CoreRenderer.makeTrusted("sqlite", (plan) => renderSqlitePlan(plan, { valueMappings: options.valueMappings })),
|
|
207
|
+
options.driver,
|
|
208
|
+
options.driverMode,
|
|
209
|
+
options.valueMappings
|
|
210
|
+
)
|
|
211
|
+
}
|
|
212
|
+
return fromDriver(
|
|
213
|
+
options.renderer ?? CoreRenderer.makeTrusted("sqlite", (plan) => renderSqlitePlan(plan, { valueMappings: options.valueMappings })),
|
|
214
|
+
sqlClientDriver(),
|
|
215
|
+
options.driverMode,
|
|
216
|
+
options.valueMappings
|
|
217
|
+
)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** Creates a SQLite-specialized executor from a typed implementation callback. */
|
|
221
|
+
export const custom = <
|
|
222
|
+
Error = never,
|
|
223
|
+
Context = never
|
|
224
|
+
>(
|
|
225
|
+
execute: <PlanValue extends CoreQuery.QueryPlan<any, any, any, any, any, any, any, any, any, any>>(
|
|
226
|
+
plan: CoreQuery.DialectCompatiblePlan<PlanValue, "sqlite">
|
|
227
|
+
) => Effect.Effect<CoreQuery.ResultRows<PlanValue>, Error, Context>
|
|
228
|
+
): Executor<Error, Context> =>
|
|
229
|
+
CoreExecutor.make("sqlite", execute as any) as Executor<Error, Context>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export * as core from "./core.js"
|
|
2
|
+
export * as string from "./string.js"
|
|
3
|
+
export * as aggregate from "./aggregate.js"
|
|
4
|
+
export * as window from "./window.js"
|
|
5
|
+
export * as temporal from "./temporal.js"
|
|
6
|
+
|
|
7
|
+
export { coalesce } from "./core.js"
|
|
8
|
+
export { call } from "./core.js"
|
|
9
|
+
export { lower, upper, concat } from "./string.js"
|
|
10
|
+
export { count, max, min } from "./aggregate.js"
|
|
11
|
+
export { over, rowNumber, rank, denseRank } from "./window.js"
|
|
12
|
+
export {
|
|
13
|
+
currentDate,
|
|
14
|
+
currentTime,
|
|
15
|
+
currentTimestamp,
|
|
16
|
+
localTime,
|
|
17
|
+
localTimestamp,
|
|
18
|
+
now
|
|
19
|
+
} from "./temporal.js"
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type * as Schema from "effect/Schema"
|
|
2
|
+
|
|
3
|
+
import type * as Expression from "../../internal/scalar.js"
|
|
4
|
+
import type * as ExpressionAst from "../../internal/expression-ast.js"
|
|
5
|
+
import { makeExpression } from "../../internal/query.js"
|
|
6
|
+
import { sqliteDatatypes } from "../datatypes/index.js"
|
|
7
|
+
import {
|
|
8
|
+
LocalDateStringSchema,
|
|
9
|
+
LocalDateTimeStringSchema,
|
|
10
|
+
LocalTimeStringSchema,
|
|
11
|
+
type LocalDateString,
|
|
12
|
+
type LocalDateTimeString,
|
|
13
|
+
type LocalTimeString
|
|
14
|
+
} from "../../internal/runtime/value.js"
|
|
15
|
+
|
|
16
|
+
type TemporalExpression<
|
|
17
|
+
Runtime,
|
|
18
|
+
Db extends Expression.DbType.Any,
|
|
19
|
+
Name extends string
|
|
20
|
+
> = Expression.Scalar<
|
|
21
|
+
Runtime,
|
|
22
|
+
Db,
|
|
23
|
+
"never",
|
|
24
|
+
"sqlite",
|
|
25
|
+
"scalar",
|
|
26
|
+
never
|
|
27
|
+
> & {
|
|
28
|
+
readonly [ExpressionAst.TypeId]: ExpressionAst.FunctionCallNode<Name, readonly []>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const makeTemporal = <
|
|
32
|
+
Runtime,
|
|
33
|
+
Db extends Expression.DbType.Any,
|
|
34
|
+
Name extends string
|
|
35
|
+
>(
|
|
36
|
+
name: Name,
|
|
37
|
+
dbType: Db,
|
|
38
|
+
runtimeSchema: Schema.Schema<Runtime, any, any>
|
|
39
|
+
): TemporalExpression<Runtime, Db, Name> =>
|
|
40
|
+
makeExpression({
|
|
41
|
+
runtime: undefined as unknown as Runtime,
|
|
42
|
+
dbType,
|
|
43
|
+
runtimeSchema,
|
|
44
|
+
nullability: "never",
|
|
45
|
+
dialect: "sqlite",
|
|
46
|
+
kind: "scalar",
|
|
47
|
+
dependencies: {},
|
|
48
|
+
}, {
|
|
49
|
+
kind: "function",
|
|
50
|
+
name,
|
|
51
|
+
args: []
|
|
52
|
+
}) as TemporalExpression<Runtime, Db, Name>
|
|
53
|
+
|
|
54
|
+
/** SQLite current date. */
|
|
55
|
+
export const currentDate = () =>
|
|
56
|
+
makeTemporal(
|
|
57
|
+
"current_date",
|
|
58
|
+
sqliteDatatypes.date(),
|
|
59
|
+
LocalDateStringSchema
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
/** SQLite current time. */
|
|
63
|
+
export const currentTime = () =>
|
|
64
|
+
makeTemporal(
|
|
65
|
+
"current_time",
|
|
66
|
+
sqliteDatatypes.time(),
|
|
67
|
+
LocalTimeStringSchema
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
/** SQLite current timestamp. */
|
|
71
|
+
export const currentTimestamp = () =>
|
|
72
|
+
makeTemporal(
|
|
73
|
+
"current_timestamp",
|
|
74
|
+
sqliteDatatypes.timestamp(),
|
|
75
|
+
LocalDateTimeStringSchema
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
/** SQLite local time. */
|
|
79
|
+
export const localTime = () =>
|
|
80
|
+
makeTemporal(
|
|
81
|
+
"localtime",
|
|
82
|
+
sqliteDatatypes.time(),
|
|
83
|
+
LocalTimeStringSchema
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
/** SQLite local timestamp. */
|
|
87
|
+
export const localTimestamp = () =>
|
|
88
|
+
makeTemporal(
|
|
89
|
+
"localtimestamp",
|
|
90
|
+
sqliteDatatypes.timestamp(),
|
|
91
|
+
LocalDateTimeStringSchema
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
/** SQLite current instant-like timestamp. */
|
|
95
|
+
export const now = () =>
|
|
96
|
+
makeTemporal(
|
|
97
|
+
"now",
|
|
98
|
+
sqliteDatatypes.timestamp(),
|
|
99
|
+
LocalDateTimeStringSchema
|
|
100
|
+
)
|