drizzle-orm-libsql-sync 0.0.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 ADDED
@@ -0,0 +1,83 @@
1
+ # drizzle-orm-libsql-sync
2
+
3
+ A **synchronous** [Drizzle ORM](https://orm.drizzle.team) driver for
4
+ [`libsql`](https://github.com/tursodatabase/libsql-js), backed directly by the
5
+ libsql `Database` (`prepare`/`exec`) and targeting Drizzle v1's modern relations.
6
+
7
+ ## Why this exists
8
+
9
+ Drizzle ships two relevant SQLite drivers, but neither fits a sync + libsql +
10
+ modern-relations use case:
11
+
12
+ - **`drizzle-orm/libsql`** is **async** (`await db.execute(...)`). Great for
13
+ Turso over the network, but heavy for serial Node/Bun build scripts, test
14
+ seeding, and benchmarks where every row insert would otherwise be `await`ed.
15
+ - **`drizzle-orm/better-sqlite3`** is sync, but it does a top-level
16
+ `import Client from "better-sqlite3"` (forcing that dependency) and historically
17
+ targeted Drizzle's legacy relational system.
18
+
19
+ This package gives you the missing combination: a real
20
+ `BaseSQLiteDatabase<"sync", …>` whose `select()/insert()/...` return rows
21
+ directly, bound to a libsql `Database`. libsql is a SQLite superset (more `ALTER`
22
+ statements, encryption-at-rest, extensions), so it's a strong local engine for
23
+ build/CLI/test code.
24
+
25
+ > **Note:** This is for **synchronous, local** work (Node/Bun build scripts,
26
+ > fixtures, benchmarks). For your app talking to Turso over the network, keep
27
+ > using the official async `drizzle-orm/libsql`.
28
+
29
+ ## Install
30
+
31
+ ```bash
32
+ npm i drizzle-orm-libsql-sync drizzle-orm libsql
33
+ ```
34
+
35
+ `drizzle-orm` and `libsql` are peer dependencies.
36
+
37
+ ## Usage
38
+
39
+ ```ts
40
+ import Database from "libsql";
41
+ import { drizzle } from "drizzle-orm-libsql-sync";
42
+ import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
43
+
44
+ const users = sqliteTable("users", {
45
+ id: integer("id").primaryKey({ autoIncrement: true }),
46
+ name: text("name").notNull(),
47
+ });
48
+
49
+ // Pass a path…
50
+ const db = drizzle("file:local.db", { schema: { users } });
51
+
52
+ // …or an existing libsql client…
53
+ const client = new Database(":memory:");
54
+ const db2 = drizzle(client, { schema: { users } });
55
+
56
+ // …or the config-object form:
57
+ const db3 = drizzle({ client, schema: { users } });
58
+
59
+ // Synchronous — no await:
60
+ db.insert(users).values({ name: "ada" }).run();
61
+ const rows = db.select().from(users).all();
62
+ ```
63
+
64
+ ### Migrations
65
+
66
+ ```ts
67
+ import { migrate } from "drizzle-orm-libsql-sync/migrator";
68
+
69
+ migrate(db, { migrationsFolder: "./drizzle" });
70
+ ```
71
+
72
+ ### Transactions
73
+
74
+ ```ts
75
+ db.transaction((tx) => {
76
+ tx.insert(users).values({ name: "grace" }).run();
77
+ // throw to roll back; nested transactions use SAVEPOINTs
78
+ });
79
+ ```
80
+
81
+ ## License
82
+
83
+ MIT
@@ -0,0 +1,10 @@
1
+ import { Database } from "libsql";
2
+
3
+ //#region src/client.d.ts
4
+ type DrizzleSyncSQLiteBindValue = null | string | number | bigint | boolean | Uint8Array;
5
+ /** The libsql `Database` surface the sync session relies on. */
6
+ type DrizzleSyncSQLiteClient = Database;
7
+ declare function isDrizzleSyncSQLiteClient(value: unknown): value is DrizzleSyncSQLiteClient;
8
+ declare function toDrizzleSyncSQLiteClient(value: unknown): DrizzleSyncSQLiteClient;
9
+ //#endregion
10
+ export { toDrizzleSyncSQLiteClient as i, DrizzleSyncSQLiteClient as n, isDrizzleSyncSQLiteClient as r, DrizzleSyncSQLiteBindValue as t };
@@ -0,0 +1,2 @@
1
+ import { i as toDrizzleSyncSQLiteClient, n as DrizzleSyncSQLiteClient, r as isDrizzleSyncSQLiteClient, t as DrizzleSyncSQLiteBindValue } from "./client-xqwnbWL8.mjs";
2
+ export { DrizzleSyncSQLiteBindValue, DrizzleSyncSQLiteClient, isDrizzleSyncSQLiteClient, toDrizzleSyncSQLiteClient };
@@ -0,0 +1,11 @@
1
+ //#region src/client.ts
2
+ function isDrizzleSyncSQLiteClient(value) {
3
+ if (typeof value !== "object" || value === null) return false;
4
+ return typeof Reflect.get(value, "prepare") === "function" && typeof Reflect.get(value, "exec") === "function";
5
+ }
6
+ function toDrizzleSyncSQLiteClient(value) {
7
+ if (!isDrizzleSyncSQLiteClient(value)) throw new TypeError("Expected a libsql-compatible synchronous SQLite client.");
8
+ return value;
9
+ }
10
+ //#endregion
11
+ export { isDrizzleSyncSQLiteClient, toDrizzleSyncSQLiteClient };
@@ -0,0 +1,28 @@
1
+ import { n as LibsqlSyncRunResult } from "./session-DuHpmegi.mjs";
2
+ import { Database } from "libsql";
3
+ import { AnyRelations, DrizzleConfig, EmptyRelations, entityKind } from "drizzle-orm";
4
+ import { BaseSQLiteDatabase } from "drizzle-orm/sqlite-core";
5
+
6
+ //#region src/driver.d.ts
7
+ /** Config-object form accepted by the call sites. */
8
+ type LibsqlSyncDrizzleConfig<TSchema extends Record<string, unknown>, TRelations extends AnyRelations> = DrizzleConfig<TSchema, TRelations> & {
9
+ client: Database;
10
+ };
11
+ declare class LibsqlSyncDatabase<TSchema extends Record<string, unknown> = Record<string, never>, TRelations extends AnyRelations = EmptyRelations> extends BaseSQLiteDatabase<"sync", LibsqlSyncRunResult, TSchema, TRelations> {
12
+ static readonly [entityKind]: string;
13
+ $client: Database;
14
+ }
15
+ declare function drizzleImpl<TSchema extends Record<string, unknown> = Record<string, never>, TRelations extends AnyRelations = EmptyRelations>(...params: [string] | [string, DrizzleConfig<TSchema, TRelations>] | [Database] | [Database, DrizzleConfig<TSchema, TRelations>] | [LibsqlSyncDrizzleConfig<TSchema, TRelations>]): LibsqlSyncDatabase<TSchema, TRelations> & {
16
+ $client: Database;
17
+ };
18
+ /**
19
+ * Mirrors `drizzle-orm/better-sqlite3`'s `drizzle.mock` — an in-memory libsql
20
+ * database, handy for type-only fixtures and tests that never touch a real
21
+ * connection.
22
+ */
23
+ declare function mock<TSchema extends Record<string, unknown> = Record<string, never>, TRelations extends AnyRelations = EmptyRelations>(config?: DrizzleConfig<TSchema, TRelations>): LibsqlSyncDatabase<TSchema, TRelations>;
24
+ declare const drizzle: typeof drizzleImpl & {
25
+ mock: typeof mock;
26
+ };
27
+ //#endregion
28
+ export { LibsqlSyncDatabase, LibsqlSyncDrizzleConfig, drizzle };
@@ -0,0 +1,64 @@
1
+ import { toDrizzleSyncSQLiteClient } from "./client.mjs";
2
+ import { LibsqlSyncSession } from "./session.mjs";
3
+ import LibsqlDatabaseCtor from "libsql";
4
+ import { DefaultLogger, entityKind } from "drizzle-orm";
5
+ import * as V1 from "drizzle-orm/_relations";
6
+ import { BaseSQLiteDatabase, SQLiteSyncDialect } from "drizzle-orm/sqlite-core";
7
+ //#region src/driver.ts
8
+ function isAnyObject(value) {
9
+ return typeof value === "object" && value !== null;
10
+ }
11
+ function isRelationsConfig(value) {
12
+ return isAnyObject(value);
13
+ }
14
+ function isExtractedSchemaTables(value) {
15
+ return isAnyObject(value);
16
+ }
17
+ var LibsqlSyncDatabase = class extends BaseSQLiteDatabase {
18
+ static [entityKind] = "LibsqlSyncDatabase";
19
+ };
20
+ function construct(client, drizzleConfig = {}) {
21
+ const sqliteClient = toDrizzleSyncSQLiteClient(client);
22
+ const dialect = new SQLiteSyncDialect();
23
+ let logger;
24
+ if (drizzleConfig.logger === true) logger = new DefaultLogger();
25
+ else if (drizzleConfig.logger !== false) logger = drizzleConfig.logger;
26
+ let schema;
27
+ if (drizzleConfig.schema) {
28
+ const tablesConfig = V1.extractTablesRelationalConfig(drizzleConfig.schema, V1.createTableRelationsHelpers);
29
+ if (!isExtractedSchemaTables(tablesConfig.tables)) throw new TypeError("Invalid relational schema tables config");
30
+ schema = {
31
+ fullSchema: drizzleConfig.schema,
32
+ schema: tablesConfig.tables,
33
+ tableNamesMap: tablesConfig.tableNamesMap
34
+ };
35
+ }
36
+ const relations = drizzleConfig.relations ?? {};
37
+ if (!isRelationsConfig(relations)) throw new TypeError("Invalid drizzle relations config");
38
+ const db = new LibsqlSyncDatabase("sync", dialect, new LibsqlSyncSession(sqliteClient, dialect, relations, schema, { logger }), relations, schema);
39
+ db.$client = sqliteClient;
40
+ return db;
41
+ }
42
+ function isLibsqlSyncDrizzleConfig(value) {
43
+ return isAnyObject(value) && "client" in value && isAnyObject(Reflect.get(value, "client"));
44
+ }
45
+ function drizzleImpl(...params) {
46
+ const [first, second] = params;
47
+ if (typeof first === "string") return construct(new LibsqlDatabaseCtor(first), second);
48
+ if (isLibsqlSyncDrizzleConfig(first)) {
49
+ const { client, ...drizzleConfig } = first;
50
+ return construct(client, drizzleConfig);
51
+ }
52
+ return construct(first, second);
53
+ }
54
+ /**
55
+ * Mirrors `drizzle-orm/better-sqlite3`'s `drizzle.mock` — an in-memory libsql
56
+ * database, handy for type-only fixtures and tests that never touch a real
57
+ * connection.
58
+ */
59
+ function mock(config) {
60
+ return construct(new LibsqlDatabaseCtor(":memory:"), config);
61
+ }
62
+ const drizzle = Object.assign(drizzleImpl, { mock });
63
+ //#endregion
64
+ export { LibsqlSyncDatabase, drizzle };
@@ -0,0 +1,4 @@
1
+ import { i as toDrizzleSyncSQLiteClient, n as DrizzleSyncSQLiteClient, r as isDrizzleSyncSQLiteClient, t as DrizzleSyncSQLiteBindValue } from "./client-xqwnbWL8.mjs";
2
+ import { a as LibsqlSyncTransaction, i as LibsqlSyncSessionOptions, n as LibsqlSyncRunResult, r as LibsqlSyncSession, t as LibsqlSyncPreparedQuery } from "./session-DuHpmegi.mjs";
3
+ import { LibsqlSyncDatabase, LibsqlSyncDrizzleConfig, drizzle } from "./driver.mjs";
4
+ export { type DrizzleSyncSQLiteBindValue, type DrizzleSyncSQLiteClient, LibsqlSyncDatabase, LibsqlSyncDrizzleConfig, LibsqlSyncPreparedQuery, LibsqlSyncRunResult, LibsqlSyncSession, LibsqlSyncSessionOptions, LibsqlSyncTransaction, drizzle, isDrizzleSyncSQLiteClient, toDrizzleSyncSQLiteClient };
package/dist/index.mjs ADDED
@@ -0,0 +1,4 @@
1
+ import { isDrizzleSyncSQLiteClient, toDrizzleSyncSQLiteClient } from "./client.mjs";
2
+ import { LibsqlSyncPreparedQuery, LibsqlSyncSession, LibsqlSyncTransaction } from "./session.mjs";
3
+ import { LibsqlSyncDatabase, drizzle } from "./driver.mjs";
4
+ export { LibsqlSyncDatabase, LibsqlSyncPreparedQuery, LibsqlSyncSession, LibsqlSyncTransaction, drizzle, isDrizzleSyncSQLiteClient, toDrizzleSyncSQLiteClient };
@@ -0,0 +1,8 @@
1
+ import { LibsqlSyncDatabase } from "./driver.mjs";
2
+ import { AnyRelations } from "drizzle-orm";
3
+ import { MigrationConfig } from "drizzle-orm/migrator";
4
+
5
+ //#region src/migrator.d.ts
6
+ declare function migrate<TSchema extends Record<string, unknown>, TRelations extends AnyRelations>(db: LibsqlSyncDatabase<TSchema, TRelations>, config: MigrationConfig): void;
7
+ //#endregion
8
+ export { migrate };
@@ -0,0 +1,17 @@
1
+ import { readMigrationFiles } from "drizzle-orm/migrator";
2
+ //#region src/migrator.ts
3
+ function migrate(db, config) {
4
+ const migrations = readMigrationFiles(config);
5
+ const dialect = Reflect.get(db, "dialect");
6
+ const session = Reflect.get(db, "session");
7
+ if (typeof dialect !== "object" || dialect === null || !("migrate" in dialect)) throw new TypeError("Database dialect does not expose migrate()");
8
+ const migrateFn = Reflect.get(dialect, "migrate");
9
+ if (typeof migrateFn !== "function") throw new TypeError("Database dialect migrate is not a function");
10
+ Reflect.apply(migrateFn, dialect, [
11
+ migrations,
12
+ session,
13
+ config
14
+ ]);
15
+ }
16
+ //#endregion
17
+ export { migrate };
@@ -0,0 +1,66 @@
1
+ import { n as DrizzleSyncSQLiteClient } from "./client-xqwnbWL8.mjs";
2
+ import { AnyRelations, DrizzleTypeError, Logger, Query, RelationalQueryMapperConfig, entityKind } from "drizzle-orm";
3
+ import * as V1 from "drizzle-orm/_relations";
4
+ import { PreparedQueryConfig, SQLiteExecuteMethod, SQLitePreparedQuery, SQLiteSession, SQLiteSyncDialect, SQLiteTransaction, SQLiteTransactionConfig, SelectedFieldsOrdered } from "drizzle-orm/sqlite-core";
5
+ import { WithCacheConfig } from "drizzle-orm/cache/core/types";
6
+
7
+ //#region src/session.d.ts
8
+ interface LibsqlSyncSessionOptions {
9
+ logger?: Logger;
10
+ useJitMappers?: boolean;
11
+ }
12
+ interface LibsqlSyncRunResult {
13
+ changes: number;
14
+ lastInsertRowid: number | bigint;
15
+ }
16
+ type PreparedQueryConfig$1 = Omit<PreparedQueryConfig, "statement" | "run">;
17
+ declare class LibsqlSyncSession<TFullSchema extends Record<string, unknown>, TRelations extends AnyRelations, TSchema extends V1.TablesRelationalConfig> extends SQLiteSession<"sync", LibsqlSyncRunResult, TFullSchema, TRelations, TSchema> {
18
+ private client;
19
+ private relations;
20
+ private schema;
21
+ private options;
22
+ static readonly [entityKind]: string;
23
+ private logger;
24
+ constructor(client: DrizzleSyncSQLiteClient, dialect: SQLiteSyncDialect, relations: TRelations, schema: V1.RelationalSchemaConfig<TSchema> | undefined, options?: LibsqlSyncSessionOptions);
25
+ prepareQuery<T extends Omit<PreparedQueryConfig$1, "run">>(query: Query, fields: SelectedFieldsOrdered | undefined, executeMethod: SQLiteExecuteMethod, customResultMapper?: (rows: unknown[][], mapColumnValue?: (value: unknown) => unknown) => unknown, queryMetadata?: {
26
+ tables: string[];
27
+ type: "select" | "update" | "delete" | "insert";
28
+ }, _cacheConfig?: WithCacheConfig): LibsqlSyncPreparedQuery<T>;
29
+ prepareRelationalQuery<T extends Omit<PreparedQueryConfig$1, "run">>(query: Query, fields: SelectedFieldsOrdered | undefined, executeMethod: SQLiteExecuteMethod, customResultMapper: (rows: Record<string, unknown>[], mapColumnValue?: (value: unknown) => unknown) => unknown, config: RelationalQueryMapperConfig): LibsqlSyncPreparedQuery<T, true>;
30
+ transaction<T>(transaction: (tx: LibsqlSyncTransaction<TFullSchema, TRelations, TSchema>) => T, config?: SQLiteTransactionConfig): T;
31
+ }
32
+ declare class LibsqlSyncTransaction<TFullSchema extends Record<string, unknown>, TRelations extends AnyRelations, TSchema extends V1.TablesRelationalConfig> extends SQLiteTransaction<"sync", LibsqlSyncRunResult, TFullSchema, TRelations, TSchema> {
33
+ static readonly [entityKind]: string;
34
+ transaction<T>(transaction: (tx: LibsqlSyncTransaction<TFullSchema, TRelations, TSchema>) => T extends Promise<any> ? DrizzleTypeError<"Sync drivers can't use async functions in transactions!"> : T): T;
35
+ }
36
+ declare class LibsqlSyncPreparedQuery<T extends PreparedQueryConfig$1 = PreparedQueryConfig$1, TIsRqbV2 extends boolean = false> extends SQLitePreparedQuery<{
37
+ all: T["all"];
38
+ execute: T["execute"];
39
+ get: T["get"];
40
+ run: LibsqlSyncRunResult;
41
+ type: "sync";
42
+ values: T["values"];
43
+ }> {
44
+ private client;
45
+ private logger;
46
+ private fields;
47
+ private useJitMappers;
48
+ private customResultMapper?;
49
+ private isRqbV2Query?;
50
+ private rqbConfig?;
51
+ static readonly [entityKind]: string;
52
+ private jitRowMapper?;
53
+ private jitRqbMapper?;
54
+ constructor(client: DrizzleSyncSQLiteClient, query: Query, logger: Logger, queryMetadata: {
55
+ tables: string[];
56
+ type: "select" | "update" | "delete" | "insert";
57
+ } | undefined, fields: SelectedFieldsOrdered | undefined, executeMethod: SQLiteExecuteMethod, useJitMappers: boolean | undefined, customResultMapper?: ((rows: TIsRqbV2 extends true ? Record<string, unknown>[] : unknown[][]) => unknown) | undefined, isRqbV2Query?: TIsRqbV2 | undefined, rqbConfig?: RelationalQueryMapperConfig | undefined);
58
+ run(placeholderValues?: Record<string, unknown>): LibsqlSyncRunResult;
59
+ all(placeholderValues?: Record<string, unknown>): T["all"];
60
+ private allRqbV2;
61
+ get(placeholderValues?: Record<string, unknown>): T["get"];
62
+ private getRqbV2;
63
+ values(placeholderValues?: Record<string, unknown>): T["values"];
64
+ }
65
+ //#endregion
66
+ export { LibsqlSyncTransaction as a, LibsqlSyncSessionOptions as i, LibsqlSyncRunResult as n, LibsqlSyncSession as r, LibsqlSyncPreparedQuery as t };
@@ -0,0 +1,2 @@
1
+ import { a as LibsqlSyncTransaction, i as LibsqlSyncSessionOptions, n as LibsqlSyncRunResult, r as LibsqlSyncSession, t as LibsqlSyncPreparedQuery } from "./session-DuHpmegi.mjs";
2
+ export { LibsqlSyncPreparedQuery, LibsqlSyncRunResult, LibsqlSyncSession, LibsqlSyncSessionOptions, LibsqlSyncTransaction };
@@ -0,0 +1,291 @@
1
+ import "./client.mjs";
2
+ import * as drizzleRuntime from "drizzle-orm";
3
+ import { NoopLogger, entityKind, fillPlaceholders, is, makeJitQueryMapper, makeJitRqbMapper, sql } from "drizzle-orm";
4
+ import { SQLitePreparedQuery, SQLiteSession, SQLiteTransaction } from "drizzle-orm/sqlite-core";
5
+ //#region src/session.ts
6
+ function isAnyObject(value) {
7
+ return typeof value === "object" && value !== null;
8
+ }
9
+ function isPlainObject(value) {
10
+ if (typeof value !== "object" || value === null) return false;
11
+ const proto = Object.getPrototypeOf(value);
12
+ return proto === Object.prototype || proto === null;
13
+ }
14
+ /**
15
+ * Sync one-shot memoizer for the `drizzle-orm` runtime export lookups below.
16
+ * Avoids a `let cached…` module singleton while keeping the lookup off the hot
17
+ * path.
18
+ */
19
+ function onetime(fn) {
20
+ let called = false;
21
+ let value;
22
+ return () => {
23
+ if (!called) {
24
+ value = fn();
25
+ called = true;
26
+ }
27
+ return value;
28
+ };
29
+ }
30
+ function getDrizzleRuntimeFunction(exportName, validate) {
31
+ const value = Reflect.get(drizzleRuntime, exportName);
32
+ if (!validate(value)) throw new TypeError(`drizzle-orm is missing runtime export: ${exportName}`);
33
+ return value;
34
+ }
35
+ const getMapResultRow = onetime(() => getDrizzleRuntimeFunction("mapResultRow", (value) => typeof value === "function"));
36
+ function isSqliteBindValue(value) {
37
+ return value === null || typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" || value instanceof Uint8Array;
38
+ }
39
+ function toSqliteBindValues(params) {
40
+ const bindValues = [];
41
+ for (const param of params) {
42
+ if (!isSqliteBindValue(param)) throw new TypeError(`Invalid SQLite bind value: ${JSON.stringify(param)}`);
43
+ bindValues.push(param);
44
+ }
45
+ return bindValues;
46
+ }
47
+ function isRecordBooleanMap(value) {
48
+ if (value === void 0) return true;
49
+ if (!isPlainObject(value)) return false;
50
+ return Object.values(value).every((entry) => typeof entry === "boolean");
51
+ }
52
+ function isSQLiteSyncDialect(value) {
53
+ return isAnyObject(value) && "sqlToQuery" in value;
54
+ }
55
+ function getPreparedQueryInternals(instance) {
56
+ const joinsNotNullableMap = Reflect.get(instance, "joinsNotNullableMap");
57
+ if (!isRecordBooleanMap(joinsNotNullableMap)) throw new TypeError("Prepared query is missing joinsNotNullableMap");
58
+ return { joinsNotNullableMap };
59
+ }
60
+ function getSQLiteSyncDialect(instance) {
61
+ const dialect = Reflect.get(instance, "dialect");
62
+ if (!isSQLiteSyncDialect(dialect)) throw new TypeError("Missing SQLite sync dialect");
63
+ return dialect;
64
+ }
65
+ function isPreparedQueryResult(value) {
66
+ return true;
67
+ }
68
+ function isRqbV2CustomResultMapper(mapper, isRqbV2) {
69
+ return isRqbV2 === true && typeof mapper === "function";
70
+ }
71
+ function isLibsqlSyncSessionFor(value) {
72
+ return is(value, LibsqlSyncSession);
73
+ }
74
+ function getSelectedFields(fields) {
75
+ if (fields === void 0) throw new TypeError("Expected selected fields to be defined");
76
+ return fields;
77
+ }
78
+ function getRelationalQueryMapperConfig(config) {
79
+ if (config === void 0) throw new TypeError("Expected relational query mapper config to be defined");
80
+ return config;
81
+ }
82
+ var LibsqlSyncSession = class extends SQLiteSession {
83
+ client;
84
+ relations;
85
+ schema;
86
+ options;
87
+ static [entityKind] = "LibsqlSyncSession";
88
+ logger;
89
+ constructor(client, dialect, relations, schema, options = {}) {
90
+ super(dialect);
91
+ this.client = client;
92
+ this.relations = relations;
93
+ this.schema = schema;
94
+ this.options = options;
95
+ this.logger = options.logger ?? new NoopLogger();
96
+ }
97
+ prepareQuery(query, fields, executeMethod, customResultMapper, queryMetadata, _cacheConfig) {
98
+ return new LibsqlSyncPreparedQuery(this.client, query, this.logger, queryMetadata, fields, executeMethod, this.options.useJitMappers, customResultMapper);
99
+ }
100
+ prepareRelationalQuery(query, fields, executeMethod, customResultMapper, config) {
101
+ return new LibsqlSyncPreparedQuery(this.client, query, this.logger, void 0, fields, executeMethod, this.options.useJitMappers, customResultMapper, true, config);
102
+ }
103
+ transaction(transaction, config = {}) {
104
+ const tx = new LibsqlSyncTransaction("sync", getSQLiteSyncDialect(this), this, this.relations, this.schema);
105
+ this.run(sql.raw(`begin${config.behavior ? " " + config.behavior : ""}`));
106
+ try {
107
+ const result = transaction(tx);
108
+ this.run(sql`commit`);
109
+ return result;
110
+ } catch (error) {
111
+ this.run(sql`rollback`);
112
+ throw error;
113
+ }
114
+ }
115
+ };
116
+ var LibsqlSyncTransaction = class LibsqlSyncTransaction extends SQLiteTransaction {
117
+ static [entityKind] = "LibsqlSyncTransaction";
118
+ transaction(transaction) {
119
+ const dialect = getSQLiteSyncDialect(this);
120
+ const sessionValue = Reflect.get(this, "session");
121
+ if (!isLibsqlSyncSessionFor(sessionValue)) throw new TypeError("Expected LibsqlSyncSession");
122
+ const savepointName = `sp${this.nestedIndex}`;
123
+ const tx = new LibsqlSyncTransaction("sync", dialect, sessionValue, this.relations, this.schema, this.nestedIndex + 1);
124
+ sessionValue.run(sql.raw(`savepoint ${savepointName}`));
125
+ try {
126
+ const result = transaction(tx);
127
+ sessionValue.run(sql.raw(`release savepoint ${savepointName}`));
128
+ return result;
129
+ } catch (error) {
130
+ sessionValue.run(sql.raw(`rollback to savepoint ${savepointName}`));
131
+ throw error;
132
+ }
133
+ }
134
+ };
135
+ var LibsqlSyncPreparedQuery = class extends SQLitePreparedQuery {
136
+ client;
137
+ logger;
138
+ fields;
139
+ useJitMappers;
140
+ customResultMapper;
141
+ isRqbV2Query;
142
+ rqbConfig;
143
+ static [entityKind] = "LibsqlSyncPreparedQuery";
144
+ jitRowMapper;
145
+ jitRqbMapper;
146
+ constructor(client, query, logger, queryMetadata, fields, executeMethod, useJitMappers, customResultMapper, isRqbV2Query, rqbConfig) {
147
+ super("sync", executeMethod, query, void 0, queryMetadata, void 0);
148
+ this.client = client;
149
+ this.logger = logger;
150
+ this.fields = fields;
151
+ this.useJitMappers = useJitMappers;
152
+ this.customResultMapper = customResultMapper;
153
+ this.isRqbV2Query = isRqbV2Query;
154
+ this.rqbConfig = rqbConfig;
155
+ }
156
+ run(placeholderValues) {
157
+ const params = fillPlaceholders(this.query.params, placeholderValues ?? {});
158
+ this.logger.logQuery(this.query.sql, params);
159
+ const info = this.client.prepare(this.query.sql).run(...toSqliteBindValues(params));
160
+ return {
161
+ changes: info.changes,
162
+ lastInsertRowid: info.lastInsertRowid
163
+ };
164
+ }
165
+ all(placeholderValues) {
166
+ if (this.isRqbV2Query) return this.allRqbV2(placeholderValues);
167
+ const internals = getPreparedQueryInternals(this);
168
+ const { client, customResultMapper, fields, logger, query } = this;
169
+ const { joinsNotNullableMap } = internals;
170
+ if (!fields && !customResultMapper) {
171
+ const params = fillPlaceholders(query.params, placeholderValues ?? {});
172
+ logger.logQuery(query.sql, params);
173
+ const result = client.prepare(query.sql).all(...toSqliteBindValues(params));
174
+ if (isPreparedQueryResult(result)) return result;
175
+ throw new TypeError("Unexpected prepared query result");
176
+ }
177
+ const rows = this.values(placeholderValues);
178
+ if (!Array.isArray(rows)) throw new TypeError("Expected values() to return row arrays");
179
+ if (customResultMapper) {
180
+ const mapped = customResultMapper(rows);
181
+ if (isPreparedQueryResult(mapped)) return mapped;
182
+ throw new TypeError("Unexpected custom result mapper output");
183
+ }
184
+ const fieldsDefined = getSelectedFields(fields);
185
+ if (this.useJitMappers) {
186
+ const mapper = this.jitRowMapper ?? makeJitQueryMapper(fieldsDefined, joinsNotNullableMap);
187
+ this.jitRowMapper = mapper;
188
+ const mapped = mapper(rows);
189
+ if (isPreparedQueryResult(mapped)) return mapped;
190
+ throw new TypeError("Unexpected JIT mapper output");
191
+ }
192
+ const mapped = rows.map((row) => {
193
+ if (!Array.isArray(row)) throw new TypeError("Expected each row to be an array");
194
+ return getMapResultRow()(fieldsDefined, row, joinsNotNullableMap);
195
+ });
196
+ if (isPreparedQueryResult(mapped)) return mapped;
197
+ throw new TypeError("Unexpected mapped query result");
198
+ }
199
+ allRqbV2(placeholderValues) {
200
+ const { client, customResultMapper, logger, query } = this;
201
+ const params = fillPlaceholders(query.params, placeholderValues ?? {});
202
+ logger.logQuery(query.sql, params);
203
+ const rows = client.prepare(query.sql).all(...toSqliteBindValues(params));
204
+ const rqbConfig = getRelationalQueryMapperConfig(this.rqbConfig);
205
+ if (this.useJitMappers) {
206
+ const mapper = this.jitRqbMapper ?? makeJitRqbMapper(rqbConfig);
207
+ this.jitRqbMapper = mapper;
208
+ const mapped = mapper(rows);
209
+ if (isPreparedQueryResult(mapped)) return mapped;
210
+ throw new TypeError("Unexpected RQB JIT mapper output");
211
+ }
212
+ if (!isRqbV2CustomResultMapper(customResultMapper, this.isRqbV2Query)) throw new TypeError("Expected custom result mapper for RQB v2 query");
213
+ const mapped = customResultMapper(rows);
214
+ if (isPreparedQueryResult(mapped)) return mapped;
215
+ throw new TypeError("Unexpected RQB custom result mapper output");
216
+ }
217
+ get(placeholderValues) {
218
+ if (this.isRqbV2Query) return this.getRqbV2(placeholderValues);
219
+ const internals = getPreparedQueryInternals(this);
220
+ const { client, customResultMapper, fields, logger, query } = this;
221
+ const { joinsNotNullableMap } = internals;
222
+ const params = fillPlaceholders(query.params, placeholderValues ?? {});
223
+ logger.logQuery(query.sql, params);
224
+ if (!fields && !customResultMapper) {
225
+ const row = client.prepare(query.sql).get(...toSqliteBindValues(params)) ?? void 0;
226
+ if (row === void 0 || row === null) return;
227
+ if (isPreparedQueryResult(row)) return row;
228
+ throw new TypeError("Unexpected prepared query row");
229
+ }
230
+ const rows = this.values(placeholderValues);
231
+ if (!Array.isArray(rows)) throw new TypeError("Expected values() to return row arrays");
232
+ const row = rows[0];
233
+ if (!row) return;
234
+ if (customResultMapper) {
235
+ const mapped = customResultMapper(rows);
236
+ if (isPreparedQueryResult(mapped)) return mapped;
237
+ throw new TypeError("Unexpected custom result mapper output");
238
+ }
239
+ const fieldsDefined = getSelectedFields(fields);
240
+ if (this.useJitMappers) {
241
+ const mapper = this.jitRowMapper ?? makeJitQueryMapper(fieldsDefined, joinsNotNullableMap);
242
+ this.jitRowMapper = mapper;
243
+ const mappedRows = mapper([row]);
244
+ if (!Array.isArray(mappedRows)) throw new TypeError("Expected JIT mapper to return an array");
245
+ const mapped = mappedRows[0];
246
+ if (mapped === void 0) return;
247
+ if (isPreparedQueryResult(mapped)) return mapped;
248
+ throw new TypeError("Unexpected JIT mapper row");
249
+ }
250
+ if (!Array.isArray(row)) throw new TypeError("Expected row to be an array");
251
+ const mapped = getMapResultRow()(fieldsDefined, row, joinsNotNullableMap);
252
+ if (isPreparedQueryResult(mapped)) return mapped;
253
+ throw new TypeError("Unexpected mapped query row");
254
+ }
255
+ getRqbV2(placeholderValues) {
256
+ const { client, customResultMapper, logger, query } = this;
257
+ const params = fillPlaceholders(query.params, placeholderValues ?? {});
258
+ logger.logQuery(query.sql, params);
259
+ const rows = client.prepare(query.sql).all(...toSqliteBindValues(params));
260
+ const row = rows[0];
261
+ if (!row) return;
262
+ const rqbConfig = getRelationalQueryMapperConfig(this.rqbConfig);
263
+ if (this.useJitMappers) {
264
+ const mapper = this.jitRqbMapper ?? makeJitRqbMapper(rqbConfig);
265
+ this.jitRqbMapper = mapper;
266
+ const mapped = mapper(rows);
267
+ if (isPreparedQueryResult(mapped)) return mapped;
268
+ throw new TypeError("Unexpected RQB JIT mapper output");
269
+ }
270
+ if (!isRqbV2CustomResultMapper(customResultMapper, this.isRqbV2Query)) throw new TypeError("Expected custom result mapper for RQB v2 query");
271
+ const mapped = customResultMapper([row]);
272
+ if (isPreparedQueryResult(mapped)) return mapped;
273
+ throw new TypeError("Unexpected RQB custom result mapper output");
274
+ }
275
+ values(placeholderValues) {
276
+ const params = fillPlaceholders(this.query.params, placeholderValues ?? {});
277
+ this.logger.logQuery(this.query.sql, params);
278
+ const stmt = this.client.prepare(this.query.sql);
279
+ const toggled = stmt.raw(true);
280
+ let result;
281
+ try {
282
+ result = toggled.all(...toSqliteBindValues(params));
283
+ } finally {
284
+ stmt.raw(false);
285
+ }
286
+ if (isPreparedQueryResult(result)) return result;
287
+ throw new TypeError("Unexpected prepared query values");
288
+ }
289
+ };
290
+ //#endregion
291
+ export { LibsqlSyncPreparedQuery, LibsqlSyncSession, LibsqlSyncTransaction };
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "drizzle-orm-libsql-sync",
3
+ "version": "0.0.0",
4
+ "description": "A synchronous Drizzle ORM driver for libsql, backed by the libsql Database (prepare/exec) and drizzle v1 modern relations.",
5
+ "keywords": [
6
+ "drizzle",
7
+ "drizzle-orm",
8
+ "libsql",
9
+ "sqlite",
10
+ "sync",
11
+ "synchronous",
12
+ "turso"
13
+ ],
14
+ "homepage": "https://github.com/leonsilicon/drizzle-orm-libsql-sync#readme",
15
+ "bugs": {
16
+ "url": "https://github.com/leonsilicon/drizzle-orm-libsql-sync/issues"
17
+ },
18
+ "license": "MIT",
19
+ "author": "Leon Si <leon@leonsilicon.com>",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/leonsilicon/drizzle-orm-libsql-sync.git"
23
+ },
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "type": "module",
28
+ "exports": {
29
+ ".": "./dist/index.mjs",
30
+ "./client": "./dist/client.mjs",
31
+ "./driver": "./dist/driver.mjs",
32
+ "./migrator": "./dist/migrator.mjs",
33
+ "./session": "./dist/session.mjs",
34
+ "./package.json": "./package.json"
35
+ },
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "scripts": {
40
+ "build": "vp pack",
41
+ "dev": "vp pack --watch",
42
+ "test": "vp test",
43
+ "check": "vp check",
44
+ "prepublishOnly": "vp run build",
45
+ "prepare": "vp config"
46
+ },
47
+ "devDependencies": {
48
+ "@types/node": "^25.6.2",
49
+ "@typescript/native-preview": "7.0.0-dev.20260509.2",
50
+ "bumpp": "^11.1.0",
51
+ "drizzle-orm": "1.0.0-rc.4-5d5b77c",
52
+ "libsql": "^0.5.29",
53
+ "typescript": "^6.0.3",
54
+ "vite": "npm:@voidzero-dev/vite-plus-core@latest",
55
+ "vite-plus": "latest"
56
+ },
57
+ "peerDependencies": {
58
+ "drizzle-orm": "^1.0.0-rc.4",
59
+ "libsql": "^0.5.0"
60
+ },
61
+ "overrides": {
62
+ "vite": "npm:@voidzero-dev/vite-plus-core@latest",
63
+ "vitest": "4.1.9"
64
+ },
65
+ "devEngines": {
66
+ "packageManager": {
67
+ "name": "bun",
68
+ "version": "1.3.14",
69
+ "onFail": "download"
70
+ }
71
+ }
72
+ }