uql-orm 0.21.0 → 0.23.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 +5 -4
- package/dist/browser/uql-browser.min.js.map +3 -3
- package/dist/bunSql/bunSqlCockroachDialect.d.ts +2 -2
- package/dist/bunSql/bunSqlCockroachDialect.js +4 -10
- package/dist/bunSql/bunSqlPostgresDialect.d.ts +2 -2
- package/dist/bunSql/bunSqlPostgresDialect.js +4 -10
- package/dist/cockroachdb/cockroachDialect.d.ts +20 -4
- package/dist/cockroachdb/cockroachDialect.js +33 -18
- package/dist/d1/d1Querier.d.ts +4 -3
- package/dist/d1/d1Querier.js +0 -3
- package/dist/d1/d1SqliteDialect.d.ts +7 -0
- package/dist/d1/d1SqliteDialect.js +9 -0
- package/dist/dialect/abstractDialect.d.ts +8 -3
- package/dist/dialect/abstractDialect.js +9 -4
- package/dist/dialect/abstractSqlDialect.d.ts +49 -8
- package/dist/dialect/abstractSqlDialect.js +95 -47
- package/dist/dialect/index.d.ts +1 -0
- package/dist/dialect/index.js +1 -0
- package/dist/dialect/indexSqlDialect.d.ts +57 -0
- package/dist/dialect/indexSqlDialect.js +101 -0
- package/dist/dialect/mysqlLikeSqlDialect.d.ts +26 -1
- package/dist/dialect/mysqlLikeSqlDialect.js +57 -1
- package/dist/dialect/pgLikeSqlDialect.d.ts +37 -22
- package/dist/dialect/pgLikeSqlDialect.js +97 -68
- package/dist/dialect/vectorCast.d.ts +21 -0
- package/dist/dialect/vectorCast.js +28 -0
- package/dist/dialect/vectorSqlDialect.d.ts +10 -3
- package/dist/dialect/vectorSqlDialect.js +19 -8
- package/dist/entity/decorator/bag.d.ts +35 -0
- package/dist/entity/decorator/bag.js +54 -0
- package/dist/entity/decorator/entity.d.ts +28 -2
- package/dist/entity/decorator/entity.js +40 -2
- package/dist/entity/decorator/members.d.ts +51 -0
- package/dist/entity/decorator/members.js +51 -0
- package/dist/entity/index.d.ts +3 -1
- package/dist/entity/index.js +3 -1
- package/dist/entity/metadata/definition.d.ts +23 -8
- package/dist/entity/metadata/definition.js +56 -100
- package/dist/http/contract.js +1 -2
- package/dist/http/handler.js +5 -26
- package/dist/http/query.js +1 -1
- package/dist/libsql/libsqlDialect.d.ts +12 -2
- package/dist/libsql/libsqlDialect.js +14 -2
- package/dist/libsql/libsqlQuerier.d.ts +9 -22
- package/dist/libsql/libsqlQuerier.js +9 -85
- package/dist/libsql/libsqlQuerierPool.d.ts +10 -8
- package/dist/libsql/libsqlQuerierPool.js +17 -15
- package/dist/maria/mariaDialect.d.ts +26 -4
- package/dist/maria/mariaDialect.js +54 -15
- package/dist/migrate/acquireQuerierForMigrations.d.ts +13 -1
- package/dist/migrate/acquireQuerierForMigrations.js +28 -0
- package/dist/migrate/builder/migrationBuilder.d.ts +9 -29
- package/dist/migrate/builder/migrationBuilder.js +58 -76
- package/dist/migrate/builder/splitSqlStatements.d.ts +0 -2
- package/dist/migrate/builder/splitSqlStatements.js +0 -2
- package/dist/migrate/builder/tableBuilder.d.ts +12 -2
- package/dist/migrate/builder/tableBuilder.js +71 -119
- package/dist/migrate/builder/types.d.ts +30 -41
- package/dist/migrate/cli-config.js +24 -8
- package/dist/migrate/cli.d.ts +3 -2
- package/dist/migrate/cli.js +26 -49
- package/dist/migrate/codegen/entityCodeGenerator.d.ts +0 -4
- package/dist/migrate/codegen/entityCodeGenerator.js +8 -67
- package/dist/migrate/codegen/fieldOptionsSource.d.ts +10 -0
- package/dist/migrate/codegen/fieldOptionsSource.js +55 -0
- package/dist/migrate/codegen/index.d.ts +0 -3
- package/dist/migrate/codegen/index.js +0 -6
- package/dist/migrate/drift/driftDetector.d.ts +10 -1
- package/dist/migrate/drift/driftDetector.js +22 -5
- package/dist/migrate/generator/indexNodeToSchema.d.ts +9 -0
- package/dist/migrate/generator/indexNodeToSchema.js +14 -0
- package/dist/migrate/generator/mongoCommand.d.ts +57 -0
- package/dist/migrate/generator/mongoCommand.js +26 -0
- package/dist/migrate/generator/mongoSchemaGenerator.d.ts +9 -20
- package/dist/migrate/generator/mongoSchemaGenerator.js +40 -82
- package/dist/migrate/index.d.ts +0 -1
- package/dist/migrate/index.js +0 -1
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +30 -11
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +61 -57
- package/dist/migrate/introspection/baseSqlIntrospector.d.ts +0 -1
- package/dist/migrate/introspection/baseSqlIntrospector.js +3 -12
- package/dist/migrate/introspection/mongoIntrospector.js +9 -15
- package/dist/migrate/introspection/mysqlIntrospector.d.ts +5 -8
- package/dist/migrate/introspection/mysqlIntrospector.js +4 -10
- package/dist/migrate/introspection/postgresIntrospector.d.ts +5 -8
- package/dist/migrate/introspection/postgresIntrospector.js +4 -10
- package/dist/migrate/introspection/sqliteIntrospector.d.ts +6 -5
- package/dist/migrate/introspection/sqliteIntrospector.js +26 -18
- package/dist/migrate/migrator.d.ts +23 -3
- package/dist/migrate/migrator.js +101 -150
- package/dist/migrate/schemaGenerator.d.ts +26 -37
- package/dist/migrate/schemaGenerator.js +69 -174
- package/dist/migrate/schemaGeneratorAsync.d.ts +2 -2
- package/dist/migrate/schemaGeneratorAsync.js +3 -3
- package/dist/migrate/storage/databaseStorage.d.ts +2 -0
- package/dist/migrate/storage/databaseStorage.js +12 -27
- package/dist/mongo/mongoDialect.d.ts +2 -0
- package/dist/mongo/mongoDialect.js +14 -3
- package/dist/mongo/mongodbQuerier.js +171 -229
- package/dist/mysql/mysqlDialect.d.ts +8 -0
- package/dist/mysql/mysqlDialect.js +13 -0
- package/dist/nestjs/uqlContextInterceptor.js +58 -22
- package/dist/nestjs/uqlModule.d.ts +2 -11
- package/dist/nestjs/uqlModule.js +93 -44
- package/dist/postgres/postgresDialect.js +2 -2
- package/dist/querier/abstractQuerier.d.ts +28 -0
- package/dist/querier/abstractQuerier.js +47 -22
- package/dist/querier/abstractQuerierPool.d.ts +3 -0
- package/dist/querier/abstractQuerierPool.js +5 -3
- package/dist/querier/abstractSqlQuerier.d.ts +1 -3
- package/dist/querier/abstractSqlQuerier.js +48 -96
- package/dist/querier/index.d.ts +3 -1
- package/dist/querier/index.js +3 -1
- package/dist/querier/querierContext.browser.d.ts +12 -0
- package/dist/querier/querierContext.browser.js +18 -0
- package/dist/querier/querierContext.d.ts +22 -0
- package/dist/querier/querierContext.js +42 -0
- package/dist/querier/queryError.d.ts +22 -0
- package/dist/querier/queryError.js +20 -0
- package/dist/querier/transactional.d.ts +26 -0
- package/dist/querier/transactional.js +43 -0
- package/dist/schema/canonicalType.d.ts +14 -2
- package/dist/schema/canonicalType.js +41 -31
- package/dist/schema/index.d.ts +1 -1
- package/dist/schema/schemaASTBuilder.d.ts +9 -2
- package/dist/schema/schemaASTBuilder.js +58 -49
- package/dist/schema/types.d.ts +10 -58
- package/dist/sqlite/abstractSqliteQuerier.d.ts +46 -0
- package/dist/sqlite/abstractSqliteQuerier.js +44 -0
- package/dist/sqlite/bunSqliteAdapter.bun.d.ts +26 -0
- package/dist/sqlite/bunSqliteAdapter.bun.js +25 -0
- package/dist/sqlite/hranaQuerier.d.ts +54 -0
- package/dist/sqlite/hranaQuerier.js +68 -0
- package/dist/sqlite/hranaQuerierPool.d.ts +21 -0
- package/dist/sqlite/hranaQuerierPool.js +25 -0
- package/dist/sqlite/index.d.ts +3 -1
- package/dist/sqlite/index.js +3 -1
- package/dist/sqlite/localSqliteQuerierPool.d.ts +31 -0
- package/dist/sqlite/localSqliteQuerierPool.js +34 -0
- package/dist/sqlite/nodeSqliteAdapter.d.ts +35 -0
- package/dist/sqlite/nodeSqliteAdapter.js +28 -0
- package/dist/sqlite/nodeSqliteQuerierPool.d.ts +28 -0
- package/dist/sqlite/nodeSqliteQuerierPool.js +29 -0
- package/dist/sqlite/sqliteDialect.d.ts +18 -5
- package/dist/sqlite/sqliteDialect.js +23 -36
- package/dist/sqlite/sqliteQuerier.d.ts +16 -9
- package/dist/sqlite/sqliteQuerier.js +4 -27
- package/dist/sqlite/sqliteQuerierPool.d.ts +11 -14
- package/dist/sqlite/sqliteQuerierPool.js +16 -24
- package/dist/turso/index.d.ts +3 -0
- package/dist/turso/index.js +3 -0
- package/dist/turso/local.d.ts +3 -0
- package/dist/turso/local.js +3 -0
- package/dist/turso/tursoDialect.d.ts +15 -0
- package/dist/turso/tursoDialect.js +18 -0
- package/dist/turso/tursoLocalQuerier.d.ts +25 -0
- package/dist/turso/tursoLocalQuerier.js +20 -0
- package/dist/turso/tursoLocalQuerierPool.d.ts +32 -0
- package/dist/turso/tursoLocalQuerierPool.js +39 -0
- package/dist/turso/tursoQuerier.d.ts +10 -0
- package/dist/turso/tursoQuerier.js +10 -0
- package/dist/turso/tursoQuerierPool.d.ts +39 -0
- package/dist/turso/tursoQuerierPool.js +38 -0
- package/dist/type/config.d.ts +0 -6
- package/dist/type/dialect.d.ts +12 -4
- package/dist/type/dialect.js +7 -1
- package/dist/type/entity.d.ts +154 -26
- package/dist/type/migration.d.ts +32 -23
- package/dist/type/querier.d.ts +6 -0
- package/dist/type/vector.d.ts +5 -2
- package/dist/util/hook.util.js +1 -1
- package/dist/util/index.d.ts +1 -0
- package/dist/util/index.js +1 -0
- package/dist/util/indexColumn.util.d.ts +6 -0
- package/dist/util/indexColumn.util.js +26 -0
- package/package.json +21 -16
- package/dist/entity/decorator/field.d.ts +0 -2
- package/dist/entity/decorator/field.js +0 -7
- package/dist/entity/decorator/filter.d.ts +0 -7
- package/dist/entity/decorator/filter.js +0 -11
- package/dist/entity/decorator/hook.d.ts +0 -7
- package/dist/entity/decorator/hook.js +0 -14
- package/dist/entity/decorator/id.d.ts +0 -2
- package/dist/entity/decorator/id.js +0 -7
- package/dist/entity/decorator/index-decorator.d.ts +0 -29
- package/dist/entity/decorator/index-decorator.js +0 -26
- package/dist/entity/decorator/index.d.ts +0 -8
- package/dist/entity/decorator/index.js +0 -8
- package/dist/entity/decorator/relation.d.ts +0 -8
- package/dist/entity/decorator/relation.js +0 -19
- package/dist/migrate/codegen/entityMerger.d.ts +0 -114
- package/dist/migrate/codegen/entityMerger.js +0 -293
- package/dist/migrate/codegen/migrationCodeGenerator.d.ts +0 -61
- package/dist/migrate/codegen/migrationCodeGenerator.js +0 -355
- package/dist/migrate/codegen/smartRelationDetector.d.ts +0 -47
- package/dist/migrate/codegen/smartRelationDetector.js +0 -134
- package/dist/migrate/generator/index.d.ts +0 -2
- package/dist/migrate/generator/index.js +0 -2
- package/dist/migrate/sync/index.d.ts +0 -6
- package/dist/migrate/sync/index.js +0 -6
- package/dist/migrate/sync/schemaSync.d.ts +0 -131
- package/dist/migrate/sync/schemaSync.js +0 -259
- package/dist/querier/decorator/index.d.ts +0 -4
- package/dist/querier/decorator/index.js +0 -4
- package/dist/querier/decorator/injectQuerier.d.ts +0 -3
- package/dist/querier/decorator/injectQuerier.js +0 -33
- package/dist/querier/decorator/log.d.ts +0 -32
- package/dist/querier/decorator/log.js +0 -52
- package/dist/querier/decorator/serialized.d.ts +0 -6
- package/dist/querier/decorator/serialized.js +0 -13
- package/dist/querier/decorator/transactional.d.ts +0 -6
- package/dist/querier/decorator/transactional.js +0 -48
- package/dist/sqlite/betterSqlite3Dialect.d.ts +0 -9
- package/dist/sqlite/betterSqlite3Dialect.js +0 -9
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
<h3>The smartest TypeScript ORM</h3>
|
|
11
11
|
|
|
12
|
-
<p>Type-safe to the leaf, serializable queries, no codegen, <a href="https://uql-orm.dev/benchmark">extremely fast</a>, and
|
|
12
|
+
<p>Type-safe to the leaf, serializable queries, no codegen, <a href="https://uql-orm.dev/benchmark">extremely fast</a>, and unified API across Postgres, CockroachDB, MySQL, SQLite, MongoDB, MariaDB, and the edge.</p>
|
|
13
13
|
|
|
14
14
|
<p>
|
|
15
15
|
<a href="https://uql-orm.dev"><b>Website</b></a> ·
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
---
|
|
30
30
|
|
|
31
31
|
```sh
|
|
32
|
-
npm install uql-orm pg # or mysql2, mariadb, better-sqlite3, mongodb, @libsql/client
|
|
32
|
+
npm install uql-orm pg # or mysql2, mariadb, better-sqlite3, mongodb, @tursodatabase/serverless, @libsql/client
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
Decorators also need `reflect-metadata` ([setup](https://uql-orm.dev/getting-started)); the
|
|
@@ -49,12 +49,13 @@ from the browser to the server. The same object runs on every supported database
|
|
|
49
49
|
|
|
50
50
|
## Why UQL?
|
|
51
51
|
|
|
52
|
-
- **The fastest.** Wins [all 8 categories](https://uql-orm.dev/benchmark) of our [open benchmark](https://github.com/rogerpadilla/ts-orm-benchmark), beating even query builders like Knex and Kysely: ~2.
|
|
52
|
+
- **The fastest.** Wins [all 8 categories](https://uql-orm.dev/benchmark) of our [open benchmark](https://github.com/rogerpadilla/ts-orm-benchmark), beating even query builders like Knex and Kysely: ~2.3× faster than the runner-up on average, close to 4M ops/s on simple SELECTs.
|
|
53
53
|
- **Light.** Zero dependencies, under 1 MB installed, every dialect included.
|
|
54
54
|
- **Queries are data, not method chains.** Plain JSON in, typed rows out. There's no DSL to learn and nothing to compile.
|
|
55
55
|
- **Type-safe to the leaf.** Operators are gated per field type, and JSON/JSONB dot-paths resolve each path's value type, so `{ age: { $like: 'x' } }` or a typo'd path is a compile error instead of a runtime surprise.
|
|
56
56
|
- **No codegen.** Entities are TypeScript classes, so your code *is* the schema. No `.prisma` file to regenerate, no generated client to keep in sync.
|
|
57
|
-
- **One API everywhere.** PostgreSQL, CockroachDB, MySQL, MariaDB, SQLite,
|
|
57
|
+
- **One API everywhere.** PostgreSQL, CockroachDB, MySQL, MariaDB, SQLite, Turso, LibSQL, Neon, Cloudflare D1, Bun SQL, and MongoDB.
|
|
58
|
+
- **First ORM with a native Turso driver.** Turso Cloud over pure `fetch()` with zero native dependencies, so it runs on Cloudflare Workers and Vercel Edge, plus the embedded Rust engine for local-first apps.
|
|
58
59
|
- **The hard things are built in.** [Semantic and vector search](https://uql-orm.dev/ai-semantic-search), [non-bypassable multi-tenant filters](https://uql-orm.dev/multi-tenancy), [entity-first migrations](https://uql-orm.dev/migrations), [soft-delete with restore](https://uql-orm.dev/entities/soft-delete), [streaming](https://uql-orm.dev/querying/streaming), and [a REST API from your entities](https://uql-orm.dev/extensions-http).
|
|
59
60
|
|
|
60
61
|
## Get started
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"import type { RequestErrorResponse, RequestSuccessResponse } from '../../http/contract.js';\nimport type { RequestOptions } from '../type/index.js';\nimport { notify } from './bus.js';\n\n/**\n * Error thrown for non-2xx responses. Carries the HTTP status so callers can key\n * behavior on it (401 redirects, 402 payment flows, error-boundary routing).\n */\nexport class RequestError extends Error {\n constructor(\n message: string,\n readonly status: number,\n ) {\n super(message);\n this.name = 'RequestError';\n }\n}\n\nexport function get<T>(url: string, opts?: RequestOptions) {\n return request<T>(url, { method: 'get' }, opts);\n}\n\nexport function post<T>(url: string, payload: unknown, opts?: RequestOptions) {\n const body = JSON.stringify(payload);\n return request<T>(url, { method: 'post', body }, opts);\n}\n\nexport function patch<T>(url: string, payload: unknown, opts?: RequestOptions) {\n const body = JSON.stringify(payload);\n return request<T>(url, { method: 'patch', body }, opts);\n}\n\nexport function put<T>(url: string, payload: unknown, opts?: RequestOptions) {\n const body = JSON.stringify(payload);\n return request<T>(url, { method: 'put', body }, opts);\n}\n\nexport function remove<T>(url: string, opts?: RequestOptions) {\n return request<T>(url, { method: 'delete' }, opts);\n}\n\n/**\n * HTTP QUERY (RFC 10008): a safe, idempotent read whose JSON query travels in the\n * request body, avoiding URL-length limits. Method name must stay uppercase\n * (fetch only normalizes the classic verbs).\n */\nexport function query<T>(url: string, payload: unknown, opts?: RequestOptions) {\n const body = JSON.stringify(payload);\n return request<T>(url, { method: 'QUERY', body }, opts);\n}\n\nfunction request<T>(url: string, init: RequestInit, opts?: RequestOptions) {\n notify({ phase: 'start', opts });\n\n init.headers = {\n accept: 'application/json',\n 'content-type': 'application/json',\n ...opts?.headers,\n };\n if (opts?.signal) {\n init.signal = opts.signal;\n }\n\n return fetch(url, init)\n .then((rawResp) =>\n rawResp.json().then((resp: unknown) => {\n const isSuccess = rawResp.status >= 200 && rawResp.status < 300;\n if (isSuccess) {\n notify({ phase: 'success', opts });\n return resp as RequestSuccessResponse<T>;\n }\n const errorResp = resp as Partial<RequestErrorResponse> | undefined;\n const error = {\n message: errorResp?.error?.message ?? rawResp.statusText,\n code: errorResp?.error?.code ?? rawResp.status,\n };\n notify({ phase: 'error', error, opts });\n throw new RequestError(error.message, error.code);\n }),\n )\n .finally(() => {\n notify({ phase: 'complete', opts });\n });\n}\n",
|
|
7
7
|
"import type { FieldKey, FieldOptions } from '../type/index.js';\n\nexport function throwPendingTransaction(): never {\n throw TypeError('pending transaction');\n}\n\nexport function throwNoPendingTransaction(): never {\n throw TypeError('not a pending transaction');\n}\n\nexport function clone<T>(value: T): T {\n if (typeof value !== 'object' || value === null) {\n return value;\n }\n if (Array.isArray(value)) {\n return value.map((it) => clone(it)) as T;\n }\n return { ...value };\n}\n\n/** Whether `obj` has at least one enumerable key. Narrows away `undefined`/`null` for callers. */\nexport function hasKeys<T>(obj: T): obj is NonNullable<T> {\n if (typeof obj !== 'object' || obj === null) return false;\n for (const _ in obj) return true;\n return false;\n}\n\n/** Whether `obj` has at least two enumerable keys. */\nexport function hasMultipleKeys(obj: object): boolean {\n let count = 0;\n for (const _ in obj) {\n if (++count > 1) return true;\n }\n return false;\n}\n\n/**\n * Whether any enumerable key of `obj` satisfies `pred`, short-circuiting on the first match\n * without materializing a key array (unlike `Object.keys(obj).some(pred)`).\n */\nexport function someKey(obj: object, pred: (key: string) => boolean): boolean {\n for (const key in obj) {\n if (pred(key)) return true;\n }\n return false;\n}\n\n/** Whether any enumerable value of `obj` satisfies `pred`, short-circuiting like {@link someKey}. */\nexport function someValue(obj: object, pred: (value: unknown) => boolean): boolean {\n return someKey(obj, (key) => pred((obj as Record<string, unknown>)[key]));\n}\n\nconst isOperatorKey = (key: string) => key.startsWith('$');\n\n/**\n * Whether `value` is a non-empty object whose keys are query/update operators (`$eq`, `$push`, ...).\n * The single source of this test: the SQL dialects, the MongoDB dialect and the `$elemMatch` walker\n * all classify operator objects with it, and they used to disagree about `{}`.\n */\nexport function isOperatorObject(value: unknown): value is Record<string, unknown> {\n return hasKeys(value) && !Array.isArray(value) && someKey(value, isOperatorKey);\n}\n\n/** Whether every key of the non-empty object `value` is an operator (no plain field names mixed in). */\nexport function isOperatorOnlyObject(value: unknown): value is Record<string, unknown> {\n return hasKeys(value) && !Array.isArray(value) && !someKey(value, (key) => !isOperatorKey(key));\n}\n\nexport function getKeys<T extends object>(obj: T): (keyof T & string)[] {\n return obj ? (Object.keys(obj) as (keyof T & string)[]) : [];\n}\n\nexport function getFieldKeys<E>(\n fields: {\n [K in FieldKey<E>]?: FieldOptions;\n },\n): FieldKey<E>[] {\n return getKeys(fields).filter((field) => fields[field]!.eager ?? true);\n}\n",
|
|
8
8
|
"export function kebabCase(val: string): string {\n let resp = val.charAt(0).toLowerCase();\n for (let i = 1; i < val.length; ++i) {\n resp += val[i] === val[i].toUpperCase() ? '-' + val[i].toLowerCase() : val[i];\n }\n return resp;\n}\n\nexport function upperFirst(text: string): string {\n if (!text) return text;\n return text[0].toUpperCase() + text.slice(1);\n}\n\nexport function lowerFirst(text: string): string {\n if (!text) return text;\n return text[0].toLowerCase() + text.slice(1);\n}\n\nexport function snakeCase(val: string): string {\n if (val === null || val === undefined) return val as string;\n if (!val) return '';\n let resp = val.charAt(0).toLowerCase();\n for (let i = 1; i < val.length; ++i) {\n const char = val[i];\n const charLower = char.toLowerCase();\n if (char !== charLower && char === char.toUpperCase()) {\n resp += '_' + charLower;\n } else {\n resp += char;\n }\n }\n return resp;\n}\n\n/**\n * Convert a string to PascalCase (UpperCamelCase).\n * @example 'user_profile' -> 'UserProfile'\n * @example 'some-text' -> 'SomeText'\n */\nexport function pascalCase(str: string): string {\n if (!str) return '';\n return str\n .split(/[_\\s-]+/)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join('');\n}\n\n/**\n * Convert a string to camelCase.\n * @example 'user_profile' -> 'userProfile'\n * @example 'SomeText' -> 'someText'\n */\nexport function camelCase(str: string): string {\n const pascal = pascalCase(str);\n return pascal.charAt(0).toLowerCase() + pascal.slice(1);\n}\n\n/**\n * Simple singularize function for English words.\n * @example 'users' -> 'user'\n * @example 'categories' -> 'category'\n */\nexport function singularize(name: string): string {\n if (!name) return '';\n if (name.endsWith('ies')) {\n return name.slice(0, -3) + 'y';\n }\n if (name.endsWith('ses') || name.endsWith('xes') || name.endsWith('zes')) {\n return name.slice(0, -2);\n }\n if (name.endsWith('s') && !name.endsWith('ss')) {\n return name.slice(0, -1);\n }\n return name;\n}\n\n/**\n * Simple pluralize function for English words.\n * @example 'user' -> 'users'\n * @example 'category' -> 'categories'\n */\nexport function pluralize(name: string): string {\n if (!name) return '';\n if (name.endsWith('y') && name.length > 1 && !/[aeiou]/.test(name[name.length - 2])) {\n return name.slice(0, -1) + 'ies';\n }\n if (name.endsWith('s') || name.endsWith('x') || name.endsWith('z') || name.endsWith('ch') || name.endsWith('sh')) {\n return name + 'es';\n }\n return name + 's';\n}\n",
|
|
9
|
-
"import type { Type, UniversalQuerier } from '../type/index.js';\n//
|
|
10
|
-
"import type { Query, QueryOptions } from '../type/index.js';\n// specific util module
|
|
9
|
+
"import type { Type, UniversalQuerier } from '../type/index.js';\n// the specific util modules, not the barrel, so the browser bundle does not pull in entity metadata\nimport { getKeys } from '../util/object.util.js';\nimport { kebabCase } from '../util/string.util.js';\n\ntype RouteShape = {\n readonly method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n readonly path: '' | `/${string}`;\n};\n\n/**\n * Single source of truth for the CRUD-over-HTTP surface, shared by server adapters and the browser client.\n * Keys are constrained to {@link UniversalQuerier} method names, so renaming a querier method\n * (or routing a non-existent one) is a compile error.\n */\nexport const CRUD_ROUTES = {\n findMany: { method: 'GET', path: '' },\n findOne: { method: 'GET', path: '/one' },\n count: { method: 'GET', path: '/count' },\n findOneById: { method: 'GET', path: '/:id' },\n insertOne: { method: 'POST', path: '' },\n insertMany: { method: 'POST', path: '/many' },\n saveOne: { method: 'PUT', path: '' },\n saveMany: { method: 'PUT', path: '/many' },\n updateMany: { method: 'PATCH', path: '' },\n updateOneById: { method: 'PATCH', path: '/:id' },\n deleteOneById: { method: 'DELETE', path: '/:id' },\n deleteMany: { method: 'DELETE', path: '' },\n} as const satisfies Partial<Record<keyof UniversalQuerier, RouteShape>>;\n\nexport type CrudOperation = keyof typeof CRUD_ROUTES;\n\nexport type CrudRoute = (typeof CRUD_ROUTES)[CrudOperation];\n\n/**\n * `QUERY` (RFC 10008) is an alternate transport for the read operations: same semantics as the\n * GET routes, but the JSON query travels in the request body instead of the query string,\n * avoiding URL-length limits for large queries.\n */\nexport type HttpMethod = CrudRoute['method'] | 'QUERY';\n\nconst CRUD_OPS = getKeys(CRUD_ROUTES);\n\n// derived from CRUD_ROUTES (the literal-path GET routes) so the sub-paths live in exactly one place\nconst QUERY_READ_OPS: ReadonlyMap<string, CrudOperation> = new Map(\n CRUD_OPS.filter((op) => CRUD_ROUTES[op].method === 'GET' && CRUD_ROUTES[op].path !== '/:id').map((op) => [\n CRUD_ROUTES[op].path,\n op,\n ]),\n);\n\n/**\n * URL segment for an entity, e.g. `entityPath(UserProfile) === 'user-profile'`.\n */\nexport function entityPath<E>(entity: Type<E>): string {\n return kebabCase(entity.name);\n}\n\nexport type RouteMatch = {\n readonly op: CrudOperation;\n /**\n * the resolved transport method - differs from the op's canonical route method for QUERY.\n */\n readonly method: HttpMethod;\n readonly id?: string;\n};\n\n/**\n * Resolve a (method, sub-path) pair to a CRUD operation. Literal sub-paths win over `:id`.\n */\nexport function matchRoute(method: string, subPath: string | undefined): RouteMatch | undefined {\n const raw = method.toUpperCase();\n const literal = subPath === undefined ? '' : `/${subPath}`;\n if (raw === 'QUERY') {\n const op = QUERY_READ_OPS.get(literal);\n return op ? { op, method: 'QUERY' } : undefined;\n }\n // HEAD reads like GET per HTTP semantics; the server runtime omits the response body\n const verb = raw === 'HEAD' ? 'GET' : raw;\n let idOp: CrudOperation | undefined;\n for (const op of CRUD_OPS) {\n const route = CRUD_ROUTES[op];\n if (route.method !== verb) {\n continue;\n }\n if (route.path === literal) {\n return { op, method: route.method };\n }\n if (route.path === '/:id') {\n idOp = op;\n }\n }\n return idOp && subPath !== undefined ? { op: idOp, method: CRUD_ROUTES[idOp].method, id: subPath } : undefined;\n}\n\nexport type RequestSuccessResponse<E> = {\n data: E;\n count?: number;\n};\n\nexport type RequestCountedSuccessResponse<E> = RequestSuccessResponse<E> & {\n count: number;\n};\n\nexport type RequestErrorResponse = {\n readonly error: {\n readonly message: string;\n readonly code: number;\n };\n};\n\n/**\n * Map a thrown error to the wire error envelope. Honors a numeric `status` on the error\n * (e.g. hooks throwing 403), defaults to 500; `code` mirrors the HTTP status.\n */\nexport function toErrorResponse(err: unknown): { status: number; body: RequestErrorResponse } {\n const status = err instanceof Error && 'status' in err && typeof err.status === 'number' ? err.status : 500;\n const message = err instanceof Error ? err.message : 'Internal Server Error';\n return { status, body: { error: { message, code: status } } };\n}\n",
|
|
10
|
+
"import type { Query, QueryOptions } from '../type/index.js';\n// the specific util module, not the barrel, so the browser bundle does not pull in entity metadata\nimport { getKeys } from '../util/object.util.js';\n\nconst JSON_QUERY_KEYS = [\n '$select',\n '$populate',\n '$exclude',\n '$where',\n '$sort',\n] as const satisfies readonly (keyof Query<unknown>)[];\n\n/**\n * Keys accepted from the wire - query structure ({@link Query}) plus the `hardDelete`/`count` scalar\n * flags. Anything else (e.g. `filters`, `context`, `$entity`) is dropped so a remote client can't\n * bypass a security filter or inject ambient context - those are server-only. The `satisfies` ties\n * every entry to a real query/option key, so a typo or a renamed option fails to compile.\n */\nconst ALLOWED_QUERY_KEYS = new Set<string>([...JSON_QUERY_KEYS, '$skip', '$limit', 'hardDelete', 'count'] satisfies (\n | keyof Query<unknown>\n | keyof Pick<QueryOptions, 'hardDelete'>\n | 'count'\n)[]);\n\n/**\n * Parse raw query-string entries (with JSON-stringified values) into a UQL query object.\n * Symmetric counterpart of {@link stringifyQuery}. Only {@link ALLOWED_QUERY_KEYS} are honored.\n */\nexport function parseQueryParams(params: Record<string, unknown> = {}): Query<unknown> {\n const query: Record<string, unknown> = {};\n for (const key of getKeys(params)) {\n if (ALLOWED_QUERY_KEYS.has(key)) {\n query[key] = params[key];\n }\n }\n\n for (const key of JSON_QUERY_KEYS) {\n const value = query[key];\n if (typeof value === 'string') {\n try {\n query[key] = JSON.parse(value);\n } catch {\n throw Object.assign(new SyntaxError(`invalid JSON in '${key}'`), { status: 400 });\n }\n }\n }\n\n query['$where'] ??= {};\n\n if (query['$skip']) {\n query['$skip'] = Number(query['$skip']);\n }\n if (query['$limit']) {\n query['$limit'] = Number(query['$limit']);\n }\n\n return query as Query<unknown>;\n}\n\n/**\n * Serialize a UQL query object into a percent-encoded query string where object values\n * are JSON-stringified. Symmetric counterpart of {@link parseQueryParams}.\n */\nexport function stringifyQuery(query?: Record<string, unknown>): string {\n if (!query) {\n return '';\n }\n const params = new URLSearchParams();\n for (const key of getKeys(query)) {\n const value = query[key];\n if (value === undefined) {\n continue;\n }\n params.append(key, typeof value === 'object' && value !== null ? JSON.stringify(value) : String(value));\n }\n const qs = params.toString();\n return qs ? `?${qs}` : '';\n}\n",
|
|
11
11
|
"import {\n CRUD_ROUTES,\n entityPath,\n type HttpMethod,\n type RequestCountedSuccessResponse,\n type RequestSuccessResponse,\n} from '../../http/contract.js';\nimport { stringifyQuery } from '../../http/query.js';\nimport type { IdValue, Query, QueryOne, QueryOptions, QuerySearch, Type, UpdatePayload } from '../../type/index.js';\nimport { get, query as httpQuery, patch, post, put, remove } from '../http/index.js';\nimport type { ClientQuerier, RequestFindOptions, RequestOptions } from '../type/index.js';\n\nexport type HttpQuerierDefaults = {\n /**\n * headers sent with every request from this instance, merged under per-call headers.\n * Create one instance per request (e.g. during SSR) to scope auth headers safely.\n */\n readonly headers?: Record<string, string>;\n /**\n * transport for read queries (findOne, findMany, count). 'QUERY' (RFC 10008) sends the\n * JSON query in the request body, avoiding URL-length limits for large queries; requires\n * infrastructure (proxies, CDNs) that forwards the QUERY method. Defaults to 'GET'.\n */\n readonly readMethod?: Extract<HttpMethod, 'GET' | 'QUERY'>;\n};\n\nexport class HttpQuerier implements ClientQuerier {\n constructor(\n readonly basePath: string,\n readonly defaults: HttpQuerierDefaults = {},\n ) {}\n\n findOneById<E extends object>(\n entity: Type<E>,\n id: IdValue<E>,\n q?: QueryOne<E>,\n opts?: RequestOptions,\n ): Promise<RequestSuccessResponse<E | undefined>> {\n const basePath = this.getBasePath(entity);\n const qs = stringifyQuery(q);\n return get<E | undefined>(`${basePath}/${id}${qs}`, this.buildOptions(opts));\n }\n\n findOne<E extends object>(\n entity: Type<E>,\n q: QueryOne<E>,\n opts?: RequestOptions,\n ): Promise<RequestSuccessResponse<E | undefined>> {\n return this.read<E | undefined>(`${this.getBasePath(entity)}${CRUD_ROUTES.findOne.path}`, q, opts);\n }\n\n findMany<E extends object>(\n entity: Type<E>,\n q: Query<E>,\n opts?: RequestFindOptions,\n ): Promise<RequestSuccessResponse<E[]>> {\n const data: Query<E> & { count?: boolean } = { ...q };\n if (opts?.count) {\n data.count = true;\n }\n return this.read<E[]>(this.getBasePath(entity), data, opts);\n }\n\n async findManyAndCount<E extends object>(\n entity: Type<E>,\n q: Query<E>,\n opts?: RequestFindOptions,\n ): Promise<RequestCountedSuccessResponse<E[]>> {\n const response = await this.findMany(entity, q, { ...opts, count: true });\n if (typeof response.count !== 'number') {\n throw new TypeError('findManyAndCount response has an invalid count');\n }\n return { ...response, count: response.count };\n }\n\n count<E extends object>(entity: Type<E>, q?: QuerySearch<E>, opts?: RequestOptions) {\n return this.read<number>(`${this.getBasePath(entity)}${CRUD_ROUTES.count.path}`, q, opts);\n }\n\n insertOne<E extends object>(entity: Type<E>, payload: E, opts?: RequestOptions) {\n const basePath = this.getBasePath(entity);\n return post<IdValue<E> | undefined>(basePath, payload, this.buildOptions(opts));\n }\n\n insertMany<E extends object>(entity: Type<E>, payload: E[], opts?: RequestOptions) {\n const basePath = this.getBasePath(entity);\n return post<IdValue<E>[]>(`${basePath}${CRUD_ROUTES.insertMany.path}`, payload, this.buildOptions(opts));\n }\n\n updateOneById<E extends object>(entity: Type<E>, id: IdValue<E>, payload: UpdatePayload<E>, opts?: RequestOptions) {\n const basePath = this.getBasePath(entity);\n return patch<number>(`${basePath}/${id}`, payload, this.buildOptions(opts));\n }\n\n updateMany<E extends object>(entity: Type<E>, q: QuerySearch<E>, payload: UpdatePayload<E>, opts?: RequestOptions) {\n const basePath = this.getBasePath(entity);\n const qs = stringifyQuery(q);\n return patch<number>(`${basePath}${qs}`, payload, this.buildOptions(opts));\n }\n\n saveOne<E extends object>(entity: Type<E>, payload: E, opts?: RequestOptions) {\n const basePath = this.getBasePath(entity);\n return put<IdValue<E>>(basePath, payload, this.buildOptions(opts));\n }\n\n saveMany<E extends object>(entity: Type<E>, payload: E[], opts?: RequestOptions) {\n const basePath = this.getBasePath(entity);\n return put<IdValue<E>[]>(`${basePath}${CRUD_ROUTES.saveMany.path}`, payload, this.buildOptions(opts));\n }\n\n deleteOneById<E extends object>(entity: Type<E>, id: IdValue<E>, opts: QueryOptions & RequestOptions = {}) {\n const basePath = this.getBasePath(entity);\n const qs = opts.hardDelete ? stringifyQuery({ hardDelete: opts.hardDelete }) : '';\n return remove<number>(`${basePath}/${id}${qs}`, this.buildOptions(opts));\n }\n\n deleteMany<E extends object>(entity: Type<E>, q: QuerySearch<E>, opts: QueryOptions & RequestOptions = {}) {\n const basePath = this.getBasePath(entity);\n const qs = stringifyQuery(opts.hardDelete ? { ...q, hardDelete: opts.hardDelete } : q);\n return remove<number>(`${basePath}${qs}`, this.buildOptions(opts));\n }\n\n getBasePath<E>(entity: Type<E>) {\n return `${this.basePath}/${entityPath(entity)}`;\n }\n\n protected read<T>(path: string, q: Record<string, unknown> | undefined, opts?: RequestOptions) {\n if (this.defaults.readMethod === 'QUERY') {\n return httpQuery<T>(path, q ?? {}, this.buildOptions(opts));\n }\n return get<T>(`${path}${stringifyQuery(q)}`, this.buildOptions(opts));\n }\n\n protected buildOptions(opts?: RequestOptions): RequestOptions | undefined {\n if (!this.defaults.headers && !opts?.headers) {\n return opts;\n }\n return { ...opts, headers: { ...this.defaults.headers, ...opts?.headers } };\n }\n}\n",
|
|
12
12
|
"import { HttpQuerier } from './querier/httpQuerier.js';\nimport type { ClientQuerier, ClientQuerierPool } from './type/index.js';\n\nlet defaultPool: ClientQuerierPool = {\n getQuerier: () => new HttpQuerier('/api'),\n};\n\nexport function setQuerierPool<T extends ClientQuerierPool>(pool: T) {\n defaultPool = pool;\n}\n\nexport function getQuerierPool(): ClientQuerierPool {\n return defaultPool;\n}\n\nexport function getQuerier(): ClientQuerier {\n return getQuerierPool().getQuerier();\n}\n"
|
|
13
13
|
],
|
|
14
|
-
"mappings": "AAEA,IAAM,EAAkC,CAAC,EAElC,SAAS,CAAM,CAAC,EAAyC,CAC9D,QAAW,KAAe,EACxB,EAAY,CAAY,EAIrB,SAAS,CAAE,CAAC,EAAiC,CAClD,EAAa,KAAK,CAAE,EACpB,IAAM,EAAQ,EAAa,OAAS,EACpC,MAAO,IAAY,CACjB,EAAa,OAAO,EAAO,CAAC,GCNzB,MAAM,UAAqB,KAAM,CAG3B,OAFX,WAAW,CACT,EACS,EACT,CACA,MAAM,CAAO,EAFJ,cAGT,KAAK,KAAO,eAEhB,CAEO,SAAS,CAAM,CAAC,EAAa,EAAuB,CACzD,OAAO,EAAW,EAAK,CAAE,OAAQ,KAAM,EAAG,CAAI,EAGzC,SAAS,CAAO,CAAC,EAAa,EAAkB,EAAuB,CAC5E,IAAM,EAAO,KAAK,UAAU,CAAO,EACnC,OAAO,EAAW,EAAK,CAAE,OAAQ,OAAQ,MAAK,EAAG,CAAI,EAGhD,SAAS,CAAQ,CAAC,EAAa,EAAkB,EAAuB,CAC7E,IAAM,EAAO,KAAK,UAAU,CAAO,EACnC,OAAO,EAAW,EAAK,CAAE,OAAQ,QAAS,MAAK,EAAG,CAAI,EAGjD,SAAS,CAAM,CAAC,EAAa,EAAkB,EAAuB,CAC3E,IAAM,EAAO,KAAK,UAAU,CAAO,EACnC,OAAO,EAAW,EAAK,CAAE,OAAQ,MAAO,MAAK,EAAG,CAAI,EAG/C,SAAS,CAAS,CAAC,EAAa,EAAuB,CAC5D,OAAO,EAAW,EAAK,CAAE,OAAQ,QAAS,EAAG,CAAI,EAQ5C,SAAS,CAAQ,CAAC,EAAa,EAAkB,EAAuB,CAC7E,IAAM,EAAO,KAAK,UAAU,CAAO,EACnC,OAAO,EAAW,EAAK,CAAE,OAAQ,QAAS,MAAK,EAAG,CAAI,EAGxD,SAAS,CAAU,CAAC,EAAa,EAAmB,EAAuB,CAQzE,GAPA,EAAO,CAAE,MAAO,QAAS,MAAK,CAAC,EAE/B,EAAK,QAAU,CACb,OAAQ,mBACR,eAAgB,sBACb,GAAM,OACX,EACI,GAAM,OACR,EAAK,OAAS,EAAK,OAGrB,OAAO,MAAM,EAAK,CAAI,EACnB,KAAK,CAAC,IACL,EAAQ,KAAK,EAAE,KAAK,CAAC,IAAkB,CAErC,GADkB,EAAQ,QAAU,KAAO,EAAQ,OAAS,IAG1D,OADA,EAAO,CAAE,MAAO,UAAW,MAAK,CAAC,EAC1B,EAET,IAAM,EAAY,EACZ,EAAQ,CACZ,QAAS,GAAW,OAAO,SAAW,EAAQ,WAC9C,KAAM,GAAW,OAAO,MAAQ,EAAQ,MAC1C,EAEA,MADA,EAAO,CAAE,MAAO,QAAS,QAAO,MAAK,CAAC,EAChC,IAAI,EAAa,EAAM,QAAS,EAAM,IAAI,EACjD,CACH,EACC,QAAQ,IAAM,CACb,EAAO,CAAE,MAAO,WAAY,MAAK,CAAC,EACnC,ECdE,SAAS,CAAyB,CAAC,EAA8B,CACtE,OAAO,EAAO,OAAO,KAAK,CAAG,EAA6B,CAAC,ECrEtD,SAAS,CAAS,CAAC,EAAqB,CAC7C,IAAI,EAAO,EAAI,OAAO,CAAC,EAAE,YAAY,EACrC,QAAS,EAAI,EAAG,EAAI,EAAI,OAAQ,EAAE,EAChC,GAAQ,EAAI,KAAO,EAAI,GAAG,YAAY,EAAI,IAAM,EAAI,GAAG,YAAY,EAAI,EAAI,GAE7E,OAAO,
|
|
14
|
+
"mappings": "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",
|
|
15
15
|
"debugId": "89C8E712B5A364FC64756E2164756E21",
|
|
16
16
|
"names": []
|
|
17
17
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CockroachDialect } from '../cockroachdb/cockroachDialect.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { DialectFeatures } from '../type/index.js';
|
|
3
3
|
/**
|
|
4
4
|
* CockroachDB Dialect specialization for the `bun:sql` driver, which routes CockroachDB
|
|
5
5
|
* connections through its own Postgres wire-protocol implementation (see
|
|
@@ -8,5 +8,5 @@ import type { DialectOptions } from '../dialect/abstractDialect.js';
|
|
|
8
8
|
* (verified directly against a live CockroachDB instance via `bun:sql`).
|
|
9
9
|
*/
|
|
10
10
|
export declare class BunSqlCockroachDialect extends CockroachDialect {
|
|
11
|
-
|
|
11
|
+
protected readonly featureOverrides: Partial<DialectFeatures>;
|
|
12
12
|
}
|
|
@@ -8,14 +8,8 @@ import { POSTGRES_WIRE_DRIVER_CAPABILITIES } from '../postgres/postgresWireDrive
|
|
|
8
8
|
* (verified directly against a live CockroachDB instance via `bun:sql`).
|
|
9
9
|
*/
|
|
10
10
|
export class BunSqlCockroachDialect extends CockroachDialect {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
...POSTGRES_WIRE_DRIVER_CAPABILITIES,
|
|
16
|
-
explicitJsonCast: true,
|
|
17
|
-
...options.driverCapabilities,
|
|
18
|
-
},
|
|
19
|
-
});
|
|
20
|
-
}
|
|
11
|
+
featureOverrides = {
|
|
12
|
+
...POSTGRES_WIRE_DRIVER_CAPABILITIES,
|
|
13
|
+
explicitJsonCast: true,
|
|
14
|
+
};
|
|
21
15
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { DialectOptions } from '../dialect/abstractDialect.js';
|
|
2
1
|
import { PostgresDialect } from '../postgres/postgresDialect.js';
|
|
2
|
+
import type { DialectFeatures } from '../type/index.js';
|
|
3
3
|
/**
|
|
4
4
|
* Postgres Dialect specialization for the `bun:sql` driver.
|
|
5
5
|
*
|
|
@@ -7,5 +7,5 @@ import { PostgresDialect } from '../postgres/postgresDialect.js';
|
|
|
7
7
|
* reliably; `PgDialect` omits the text re-cast.
|
|
8
8
|
*/
|
|
9
9
|
export declare class BunSqlPostgresDialect extends PostgresDialect {
|
|
10
|
-
|
|
10
|
+
protected readonly featureOverrides: Partial<DialectFeatures>;
|
|
11
11
|
}
|
|
@@ -7,14 +7,8 @@ import { POSTGRES_WIRE_DRIVER_CAPABILITIES } from '../postgres/postgresWireDrive
|
|
|
7
7
|
* reliably; `PgDialect` omits the text re-cast.
|
|
8
8
|
*/
|
|
9
9
|
export class BunSqlPostgresDialect extends PostgresDialect {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
...POSTGRES_WIRE_DRIVER_CAPABILITIES,
|
|
15
|
-
explicitJsonCast: true,
|
|
16
|
-
...options.driverCapabilities,
|
|
17
|
-
},
|
|
18
|
-
});
|
|
19
|
-
}
|
|
10
|
+
featureOverrides = {
|
|
11
|
+
...POSTGRES_WIRE_DRIVER_CAPABILITIES,
|
|
12
|
+
explicitJsonCast: true,
|
|
13
|
+
};
|
|
20
14
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type { DialectOptions } from '../dialect/abstractDialect.js';
|
|
2
1
|
import { PgLikeSqlDialect } from '../dialect/pgLikeSqlDialect.js';
|
|
3
|
-
import type { VectorDistance } from '../type/index.js';
|
|
2
|
+
import type { IndexFeature, IndexSchema, VectorDistance } from '../type/index.js';
|
|
4
3
|
/**
|
|
5
4
|
* CockroachDB Dialect.
|
|
6
5
|
* Shares AST/quoting/JSONB/full-text-search/vector-search/upsert logic with Postgres via
|
|
@@ -14,6 +13,23 @@ import type { VectorDistance } from '../type/index.js';
|
|
|
14
13
|
*/
|
|
15
14
|
export declare class CockroachDialect extends PgLikeSqlDialect {
|
|
16
15
|
readonly dialectName = "cockroachdb";
|
|
17
|
-
readonly
|
|
18
|
-
|
|
16
|
+
readonly vectorMetrics: ReadonlyMap<VectorDistance, {
|
|
17
|
+
op: string;
|
|
18
|
+
opsSuffix: string;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* `NULLS FIRST/LAST` answers "unimplemented: this syntax" and `jsonb_path_ops` "operator class is
|
|
22
|
+
* not supported" (both verified on v26.2), so neither is offered here.
|
|
23
|
+
*/
|
|
24
|
+
protected readonly indexFeatures: Set<IndexFeature>;
|
|
25
|
+
/**
|
|
26
|
+
* CockroachDB's vector index is native and has its own syntax: `CREATE VECTOR INDEX ... ("col"
|
|
27
|
+
* vector_cosine_ops)`, with no access-method keyword, and tuning knobs of its own names that UQL
|
|
28
|
+
* does not map. `type: 'vector'` is its trigger, the same generic value MariaDB's inline index uses.
|
|
29
|
+
*/
|
|
30
|
+
private isNativeVectorIndex;
|
|
31
|
+
protected isVectorIndex(index: IndexSchema): boolean;
|
|
32
|
+
protected indexKeyword(index: IndexSchema): string;
|
|
33
|
+
protected indexAccessMethod(index: IndexSchema): string;
|
|
34
|
+
protected indexTuning(index: IndexSchema): string;
|
|
19
35
|
}
|
|
@@ -12,24 +12,39 @@ import { PgLikeSqlDialect } from '../dialect/pgLikeSqlDialect.js';
|
|
|
12
12
|
*/
|
|
13
13
|
export class CockroachDialect extends PgLikeSqlDialect {
|
|
14
14
|
dialectName = 'cockroachdb';
|
|
15
|
-
// CockroachDB
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
['
|
|
23
|
-
['
|
|
24
|
-
['inner', 'vector_ip_ops'],
|
|
15
|
+
// CockroachDB implements 3 of pgvector's 4 metrics: `<+>` and `vector_l1_ops` throw
|
|
16
|
+
// "unimplemented: operator class ... is not supported" (verified live on v26.2), which its own docs
|
|
17
|
+
// list under "Known limitations": https://www.cockroachlabs.com/docs/stable/vector-indexes -
|
|
18
|
+
// tracked upstream at https://github.com/cockroachdb/cockroach/issues/147839. Re-check that issue
|
|
19
|
+
// before adding `l1` here; it is omitted on purpose, not an oversight.
|
|
20
|
+
vectorMetrics = new Map([
|
|
21
|
+
['cosine', { op: '<=>', opsSuffix: 'cosine' }],
|
|
22
|
+
['l2', { op: '<->', opsSuffix: 'l2' }],
|
|
23
|
+
['inner', { op: '<#>', opsSuffix: 'ip' }],
|
|
25
24
|
]);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
25
|
+
/**
|
|
26
|
+
* `NULLS FIRST/LAST` answers "unimplemented: this syntax" and `jsonb_path_ops` "operator class is
|
|
27
|
+
* not supported" (both verified on v26.2), so neither is offered here.
|
|
28
|
+
*/
|
|
29
|
+
indexFeatures = new Set(['expression', 'include']);
|
|
30
|
+
/**
|
|
31
|
+
* CockroachDB's vector index is native and has its own syntax: `CREATE VECTOR INDEX ... ("col"
|
|
32
|
+
* vector_cosine_ops)`, with no access-method keyword, and tuning knobs of its own names that UQL
|
|
33
|
+
* does not map. `type: 'vector'` is its trigger, the same generic value MariaDB's inline index uses.
|
|
34
|
+
*/
|
|
35
|
+
isNativeVectorIndex(index) {
|
|
36
|
+
return index.type === 'vector';
|
|
37
|
+
}
|
|
38
|
+
isVectorIndex(index) {
|
|
39
|
+
return this.isNativeVectorIndex(index) || super.isVectorIndex(index);
|
|
40
|
+
}
|
|
41
|
+
indexKeyword(index) {
|
|
42
|
+
return this.isNativeVectorIndex(index) ? 'VECTOR INDEX' : super.indexKeyword(index);
|
|
43
|
+
}
|
|
44
|
+
indexAccessMethod(index) {
|
|
45
|
+
return this.isNativeVectorIndex(index) ? '' : super.indexAccessMethod(index);
|
|
46
|
+
}
|
|
47
|
+
indexTuning(index) {
|
|
48
|
+
return this.isNativeVectorIndex(index) ? '' : super.indexTuning(index);
|
|
34
49
|
}
|
|
35
50
|
}
|
package/dist/d1/d1Querier.d.ts
CHANGED
|
@@ -35,11 +35,12 @@ export interface D1Database {
|
|
|
35
35
|
batch<T = unknown>(statements: D1PreparedStatement[]): Promise<D1Result<T>[]>;
|
|
36
36
|
exec(query: string): Promise<D1ExecResult>;
|
|
37
37
|
}
|
|
38
|
+
/** The only part of a D1 binding the querier uses; a full {@link D1Database} satisfies it. */
|
|
39
|
+
export type D1Preparer = Pick<D1Database, 'prepare'>;
|
|
38
40
|
export declare class D1Querier extends AbstractSqliteQuerier {
|
|
39
|
-
readonly db:
|
|
41
|
+
readonly db: D1Preparer;
|
|
40
42
|
readonly extra?: ExtraOptions | undefined;
|
|
41
|
-
constructor(db:
|
|
43
|
+
constructor(db: D1Preparer, dialect: SqliteDialect, extra?: ExtraOptions | undefined);
|
|
42
44
|
internalAll<T>(query: string, values?: unknown[]): Promise<T[]>;
|
|
43
45
|
internalRun(query: string, values?: unknown[]): Promise<import("../type/query.js").QueryUpdateResult>;
|
|
44
|
-
internalRelease(): Promise<void>;
|
|
45
46
|
}
|
package/dist/d1/d1Querier.js
CHANGED
|
@@ -6,4 +6,11 @@ import { SqliteDialect } from '../sqlite/sqliteDialect.js';
|
|
|
6
6
|
*/
|
|
7
7
|
export declare class D1SqliteDialect extends SqliteDialect {
|
|
8
8
|
readonly maxBindValues: number;
|
|
9
|
+
/**
|
|
10
|
+
* D1 loads no extensions (its allowlist is FTS5, JSON and the math functions) and has no vector
|
|
11
|
+
* functions of its own, so the sqlite-vec names inherited from {@link SqliteDialect} would compile
|
|
12
|
+
* to SQL that only fails once it reaches the edge. `raw()` is no escape hatch either, hence a
|
|
13
|
+
* message that names the product that does the job.
|
|
14
|
+
*/
|
|
15
|
+
protected appendVectorSort(): never;
|
|
9
16
|
}
|
|
@@ -7,4 +7,13 @@ import { SqliteDialect } from '../sqlite/sqliteDialect.js';
|
|
|
7
7
|
export class D1SqliteDialect extends SqliteDialect {
|
|
8
8
|
// Cloudflare D1 caps bound parameters at 100 per query.
|
|
9
9
|
maxBindValues = 100;
|
|
10
|
+
/**
|
|
11
|
+
* D1 loads no extensions (its allowlist is FTS5, JSON and the math functions) and has no vector
|
|
12
|
+
* functions of its own, so the sqlite-vec names inherited from {@link SqliteDialect} would compile
|
|
13
|
+
* to SQL that only fails once it reaches the edge. `raw()` is no escape hatch either, hence a
|
|
14
|
+
* message that names the product that does the job.
|
|
15
|
+
*/
|
|
16
|
+
appendVectorSort() {
|
|
17
|
+
throw new TypeError('Cloudflare D1 has no vector functions and cannot load sqlite-vec. Use Cloudflare Vectorize for vector search.');
|
|
18
|
+
}
|
|
10
19
|
}
|
|
@@ -20,12 +20,17 @@ export declare abstract class AbstractDialect {
|
|
|
20
20
|
* {@link DialectOptions.driverCapabilities} overrides. Each concrete dialect declares its own.
|
|
21
21
|
*/
|
|
22
22
|
protected abstract readonly featureDefaults: DialectFeatures;
|
|
23
|
+
/**
|
|
24
|
+
* How this dialect differs from the family it extends, so a subclass states only its deltas rather
|
|
25
|
+
* than repeating {@link featureDefaults} in full or injecting them through its constructor.
|
|
26
|
+
*/
|
|
27
|
+
protected readonly featureOverrides: Partial<DialectFeatures>;
|
|
23
28
|
readonly namingStrategy: NamingStrategy | undefined;
|
|
24
29
|
constructor(options?: DialectOptions);
|
|
25
30
|
/**
|
|
26
|
-
* Effective features: {@link featureDefaults}
|
|
27
|
-
* Computed lazily (and memoized)
|
|
28
|
-
* after `super()` returns.
|
|
31
|
+
* Effective features: {@link featureDefaults}, then this dialect's {@link featureOverrides}, then
|
|
32
|
+
* any per-instance {@link DialectOptions.driverCapabilities}. Computed lazily (and memoized)
|
|
33
|
+
* because both are subclass fields, initialized only after `super()` returns.
|
|
29
34
|
*/
|
|
30
35
|
get features(): DialectFeatures;
|
|
31
36
|
/**
|
|
@@ -4,6 +4,11 @@ import { applyFilters, buildQueryWhereAsMap } from '../util/dialect.util.js';
|
|
|
4
4
|
*/
|
|
5
5
|
export class AbstractDialect {
|
|
6
6
|
options;
|
|
7
|
+
/**
|
|
8
|
+
* How this dialect differs from the family it extends, so a subclass states only its deltas rather
|
|
9
|
+
* than repeating {@link featureDefaults} in full or injecting them through its constructor.
|
|
10
|
+
*/
|
|
11
|
+
featureOverrides = {};
|
|
7
12
|
namingStrategy;
|
|
8
13
|
#features;
|
|
9
14
|
constructor(options = {}) {
|
|
@@ -11,12 +16,12 @@ export class AbstractDialect {
|
|
|
11
16
|
this.namingStrategy = options.namingStrategy;
|
|
12
17
|
}
|
|
13
18
|
/**
|
|
14
|
-
* Effective features: {@link featureDefaults}
|
|
15
|
-
* Computed lazily (and memoized)
|
|
16
|
-
* after `super()` returns.
|
|
19
|
+
* Effective features: {@link featureDefaults}, then this dialect's {@link featureOverrides}, then
|
|
20
|
+
* any per-instance {@link DialectOptions.driverCapabilities}. Computed lazily (and memoized)
|
|
21
|
+
* because both are subclass fields, initialized only after `super()` returns.
|
|
17
22
|
*/
|
|
18
23
|
get features() {
|
|
19
|
-
this.#features ??= { ...this.featureDefaults, ...this.options.driverCapabilities };
|
|
24
|
+
this.#features ??= { ...this.featureDefaults, ...this.featureOverrides, ...this.options.driverCapabilities };
|
|
20
25
|
return this.#features;
|
|
21
26
|
}
|
|
22
27
|
/**
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { type EntityMeta, type FieldKey, type FieldOptions, type IsolationLevel, type JsonColumnType, type JsonUpdateOp, type Query, type QueryAggMap, type QueryAggregate, type QueryComparisonOptions, type QueryConflictPaths, type QueryContext, type QueryDialect, type QueryExclude, type QueryGroupMap, type QueryHavingMap, type QueryOptions, type QueryPager, type QueryPopulate, QueryRaw, type QueryRawFnOptions, type QuerySearch, type QuerySelect, type QuerySelectOptions, type QuerySelectValue, type QuerySizeComparisonOps, type QuerySortMap, type QueryWhere, type QueryWhereArray, type QueryWhereFieldOperatorMap, type QueryWhereMap, type QueryWhereOptions, type RelationOptions, type SqlDialectName, type SqlQueryDialect, type Type, type UpdatePayload } from '../type/index.js';
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { type EntityMeta, type FieldKey, type FieldOptions, type IsolationLevel, type JsonColumnType, type JsonUpdateOp, type Query, type QueryAggMap, type QueryAggregate, type QueryComparisonOptions, type QueryConflictPaths, type QueryContext, type QueryDialect, type QueryExclude, type QueryGroupMap, type QueryHavingMap, type QueryOptions, type QueryPager, type QueryPopulate, QueryRaw, type QueryRawFnOptions, type QuerySearch, type QuerySelect, type QuerySelectOptions, type QuerySelectValue, type QuerySizeComparisonOps, type QuerySortMap, type QueryTextSearchOptions, type QueryWhere, type QueryWhereArray, type QueryWhereFieldOperatorMap, type QueryWhereMap, type QueryWhereOptions, type RelationOptions, type SqlDialectName, type SqlQueryDialect, type Type, type UpdatePayload } from '../type/index.js';
|
|
2
|
+
import { IndexSqlDialect } from './indexSqlDialect.js';
|
|
3
|
+
/** How a column's values are bound: see {@link AbstractSqlDialect.persistKind}. */
|
|
4
|
+
type PersistKind = 'plain' | 'json' | 'vector';
|
|
5
|
+
export declare abstract class AbstractSqlDialect extends IndexSqlDialect implements QueryDialect, SqlQueryDialect {
|
|
4
6
|
abstract readonly dialectName: SqlDialectName;
|
|
5
7
|
abstract readonly escapeIdChar: '"' | '`';
|
|
6
8
|
abstract readonly serialPrimaryKey: string;
|
|
@@ -47,6 +49,18 @@ export declare abstract class AbstractSqlDialect extends VectorSqlDialect implem
|
|
|
47
49
|
returningId<E>(entity: Type<E>): string;
|
|
48
50
|
search<E>(ctx: QueryContext, entity: Type<E>, q?: Query<E>, opts?: QueryOptions): void;
|
|
49
51
|
selectFields<E>(ctx: QueryContext, entity: Type<E>, select: QuerySelectValue<E> | undefined, opts?: QuerySelectOptions, exclude?: QueryExclude<E>): void;
|
|
52
|
+
/**
|
|
53
|
+
* The expression a scalar field is read through, the plain column by default. MariaDB reads a
|
|
54
|
+
* vector column back with `VEC_ToText`, since selecting it raw yields its binary form.
|
|
55
|
+
*/
|
|
56
|
+
protected selectFieldExpr(escapedColumn: string, _field: FieldOptions): string;
|
|
57
|
+
/**
|
|
58
|
+
* The `$text` full-text predicate, which every engine spells differently: `MATCH ... AGAINST`
|
|
59
|
+
* (MySQL family), `to_tsvector @@ websearch_to_tsquery` (Postgres-wire), an FTS5 `MATCH` against
|
|
60
|
+
* the table itself (SQLite). No portable form exists, so a dialect without one says so here rather
|
|
61
|
+
* than inheriting another engine's syntax.
|
|
62
|
+
*/
|
|
63
|
+
protected appendTextSearch<E>(_ctx: QueryContext, _entity: Type<E>, _meta: EntityMeta<E>, _search: QueryTextSearchOptions<E>): void;
|
|
50
64
|
select<E>(ctx: QueryContext, entity: Type<E>, select: QuerySelectValue<E> | undefined, exclude?: QueryExclude<E>, populate?: QueryPopulate<E>, opts?: QueryOptions, distinct?: boolean, sort?: QuerySortMap<E>): void;
|
|
51
65
|
private resolveRelationAwarePrefix;
|
|
52
66
|
protected selectRelationFields<E>(ctx: QueryContext, entity: Type<E>, select: QuerySelect<E> | undefined, populate: QueryPopulate<E> | undefined, opts?: {
|
|
@@ -195,6 +209,11 @@ export declare abstract class AbstractSqlDialect extends VectorSqlDialect implem
|
|
|
195
209
|
protected havingCondition(ctx: QueryContext, expr: string, condition: QueryHavingMap[string]): void;
|
|
196
210
|
find<E>(ctx: QueryContext, entity: Type<E>, q?: Query<E>, opts?: QueryOptions): void;
|
|
197
211
|
insert<E>(ctx: QueryContext, entity: Type<E>, payload: E | E[], opts?: QueryOptions): void;
|
|
212
|
+
/**
|
|
213
|
+
* `INSERT INTO ... VALUES (...)` and nothing more. The upsert builders extend this rather than
|
|
214
|
+
* {@link insert}: their own clause has to come before the `RETURNING`, not after it.
|
|
215
|
+
*/
|
|
216
|
+
protected appendInsertValues<E>(ctx: QueryContext, entity: Type<E>, payload: E | E[], opts?: QueryOptions): void;
|
|
198
217
|
/**
|
|
199
218
|
* Emit the value for a column a payload record does not provide (the column list is the union
|
|
200
219
|
* across all records). `DEFAULT` delegates to the database default; SQLite overrides this since
|
|
@@ -202,19 +221,40 @@ export declare abstract class AbstractSqlDialect extends VectorSqlDialect implem
|
|
|
202
221
|
*/
|
|
203
222
|
protected appendDefaultInsertValue(ctx: QueryContext, _field: FieldOptions | undefined): void;
|
|
204
223
|
update<E>(ctx: QueryContext, entity: Type<E>, q: QuerySearch<E>, payload: UpdatePayload<E>, opts?: QueryOptions): void;
|
|
205
|
-
|
|
224
|
+
/**
|
|
225
|
+
* `INSERT ... ON CONFLICT (...) DO UPDATE/NOTHING RETURNING ...`, which SQLite adopted from Postgres
|
|
226
|
+
* and which every dialect here speaks except the MySQL family (see {@link MysqlLikeSqlDialect}).
|
|
227
|
+
*
|
|
228
|
+
* Two orderings matter, and they pull in opposite directions. The assignments are computed *before*
|
|
229
|
+
* the insert, because `appendInsertValues` fills `onInsert` fields into the payload and a column that
|
|
230
|
+
* exists only there - `createdAt` - must not join the update set. Their bound values are pushed
|
|
231
|
+
* *after* it, because a `?` placeholder is positional and the clause comes last in the statement.
|
|
232
|
+
* {@link PgLikeSqlDialect} overrides this: `$N` placeholders make array order irrelevant, so it can
|
|
233
|
+
* bind into the main context and skip the second one.
|
|
234
|
+
*/
|
|
235
|
+
upsert<E>(ctx: QueryContext, entity: Type<E>, conflictPaths: QueryConflictPaths<E>, payload: E | E[], extraReturning?: string): void;
|
|
236
|
+
/** How an `ON CONFLICT` assignment reads the row that was being inserted. */
|
|
237
|
+
protected readonly upsertExcluded: (columnName: string) => string;
|
|
206
238
|
protected getUpsertUpdateAssignments<E>(ctx: QueryContext, meta: EntityMeta<E>, conflictPaths: QueryConflictPaths<E>, payload: E | E[], callback?: (columnName: string) => string): string;
|
|
207
239
|
protected getUpsertConflictPathsStr<E>(meta: EntityMeta<E>, conflictPaths: QueryConflictPaths<E>): string;
|
|
208
240
|
delete<E>(ctx: QueryContext, entity: Type<E>, q: QuerySearch<E>, opts?: QueryOptions): void;
|
|
209
241
|
escapeId(val: string, forbidQualified?: boolean, addDot?: boolean): string;
|
|
210
242
|
/**
|
|
211
|
-
*
|
|
212
|
-
* {@link appendVectorValue} rather than this, so the chain runs once per
|
|
213
|
-
* and delegating back to `super` ran every check twice, measurably slowing
|
|
243
|
+
* Bind one persisted value, classifying its column on the spot. Dialects override
|
|
244
|
+
* {@link appendJsonValue} and {@link appendVectorValue} rather than this, so the chain runs once per
|
|
245
|
+
* value - overriding this and delegating back to `super` ran every check twice, measurably slowing
|
|
246
|
+
* every INSERT/UPDATE.
|
|
214
247
|
*/
|
|
215
248
|
protected formatPersistableValue(ctx: QueryContext, field: FieldOptions | undefined, value: unknown): void;
|
|
249
|
+
/**
|
|
250
|
+
* How a column's values are written. A function of the column, not of the value, so a bulk insert
|
|
251
|
+
* classifies each column once instead of re-deciding per row: a 20-row, 6-column insert asked
|
|
252
|
+
* `isJsonType` and `isVectorFieldType` 120 times to get the same six answers.
|
|
253
|
+
*/
|
|
254
|
+
protected persistKind(field: FieldOptions | undefined): PersistKind;
|
|
255
|
+
/** The one type dispatch for a persisted value, over a column kind decided by the caller. */
|
|
256
|
+
private writePersistableValue;
|
|
216
257
|
protected appendJsonValue(ctx: QueryContext, value: unknown, _type: JsonColumnType): void;
|
|
217
|
-
protected appendVectorValue(ctx: QueryContext, value: readonly unknown[]): void;
|
|
218
258
|
/**
|
|
219
259
|
* Reads `operand` as a JSON value. Passing the `?` placeholder yields the cast for a bound
|
|
220
260
|
* parameter, and passing an expression re-reads text as JSON - the same SQL either way, which is
|
|
@@ -332,3 +372,4 @@ export declare abstract class AbstractSqlDialect extends VectorSqlDialect implem
|
|
|
332
372
|
protected numericCast(expr: string): string;
|
|
333
373
|
toString(): string;
|
|
334
374
|
}
|
|
375
|
+
export {};
|