@type32/tauri-sqlite-orm 0.1.17 → 0.1.18-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 CHANGED
@@ -1,8 +1,15 @@
1
- ## tauri-sqlite-orm
1
+ ## Tauri SQLite ORM
2
2
 
3
- A Drizzle-like TypeScript ORM tailored for Tauri v2's `@tauri-apps/plugin-sql` (SQLite). Plug-and-play for Nuxt/Tauri apps: define schema in TS, run tracked migrations, and query with a soft-relations API.
3
+ A Drizzle-like TypeScript ORM tailored for Tauri v2's `@tauri-apps/plugin-sql` (SQLite). It provides a simple, type-safe query builder and migration tools to help you manage your database with ease.
4
4
 
5
- ### Install
5
+ ### Features
6
+
7
+ - **Drizzle-like Schema:** Define your database schema using a familiar, chainable API.
8
+ - **Type-Safe Query Builder:** Build SQL queries with TypeScript, ensuring type safety and autocompletion.
9
+ - **Simplified Migrations:** Keep your database schema in sync with your application's models using automatic schema detection and migration tools.
10
+ - **Lightweight & Performant:** Designed to be a thin layer over the Tauri SQL plugin, ensuring minimal overhead.
11
+
12
+ ### Installation
6
13
 
7
14
  ```bash
8
15
  bun add @type32/tauri-sqlite-orm @tauri-apps/plugin-sql
@@ -10,243 +17,155 @@ bun add @type32/tauri-sqlite-orm @tauri-apps/plugin-sql
10
17
 
11
18
  Make sure the SQL plugin is registered on the Rust side (see Tauri docs).
12
19
 
13
- ### Quick start
20
+ ### Quick Start
14
21
 
15
- ```ts
16
- import {
17
- TauriORM,
18
- defineTable,
19
- integer,
20
- text,
21
- relations,
22
- } from "tauri-sqlite-orm";
22
+ Here’s a quick example to get you started:
23
23
 
24
- const db = new TauriORM("sqlite:app.db");
24
+ ```typescript
25
+ // src/db/schema.ts
26
+ import { sqliteTable, text, integer } from "@type32/tauri-sqlite-orm";
25
27
 
26
- export const users = defineTable("users", {
27
- id: integer("id").primaryKey({ autoIncrement: true }),
28
+ export const users = sqliteTable("users", {
29
+ id: integer("id").primaryKey().autoincrement(),
28
30
  name: text("name").notNull(),
29
- email: text("email"),
31
+ email: text("email").unique(),
30
32
  });
31
33
 
32
- export const posts = defineTable("posts", {
34
+ export const posts = sqliteTable("posts", {
33
35
  id: integer("id").primaryKey(),
34
36
  content: text("content"),
35
- randomId: text("random_id").$defaultFn(() => crypto.randomUUID()),
36
- authorId: integer("author_id"),
37
+ authorId: integer("author_id").references(() => users.id),
37
38
  });
38
39
 
39
- export const usersRelations = relations(users, ({ many }) => ({
40
- posts: many(posts),
41
- }));
40
+ // src/db/index.ts
41
+ import { TauriORM } from "@type32/tauri-sqlite-orm";
42
+ import Database from "@tauri-apps/plugin-sql";
43
+ import * as schema from "./schema";
42
44
 
43
- db.configure({ users, posts }, { users: usersRelations });
44
- await db.migrateConfigured({ name: "init:users,posts" });
45
+ // Load the database
46
+ const dbInstance = await Database.load("sqlite:app.db");
45
47
 
46
- // Create
47
- await db
48
- .insert(users)
49
- .values({ name: "Dan", email: "dan@example.com" })
50
- .execute();
48
+ // Create the ORM instance
49
+ export const db = new TauriORM(dbInstance, schema);
51
50
 
52
- // Query with relations (join-based when flat)
53
- const res = await db.query.users.findMany({
54
- with: { posts: true },
55
- join: true,
56
- });
51
+ // Migrate the database if the schema has changed
52
+ await db.migrateIfDirty();
53
+
54
+ // Now you can use the ORM to interact with your database
55
+ const newUser = await db
56
+ .insert(schema.users)
57
+ .values({ name: "John Doe", email: "john.doe@example.com" });
58
+ const allUsers = await db.select(schema.users).execute();
57
59
  ```
58
60
 
59
61
  ### Documentation
60
62
 
61
- - See full docs in `docs/`:
62
- - Getting Started: `docs/getting-started.md`
63
- - Schema & Types: `docs/schema-and-types.md`
64
- - Relations: `docs/relations.md`
65
- - Queries (select): `docs/queries-select.md`
66
- - CRUD (insert): `docs/crud-insert.md`
67
- - CRUD (update): `docs/crud-update.md`
68
- - CRUD (delete): `docs/crud-delete.md`
69
- - SQL Helpers: `docs/sql-helpers.md`
70
- - Indexes & Constraints: `docs/indexes-constraints.md`
71
- - Migrations: `docs/migrations.md`
72
-
73
- ### Schema builder
74
-
75
- Chainable, Drizzle-style:
76
-
77
- ```ts
78
- import {
79
- defineTable,
80
- integer,
81
- text,
82
- real,
83
- blob,
84
- numeric,
85
- sql,
86
- } from "tauri-sqlite-orm";
87
-
88
- type Data = { foo: string; bar: number };
89
-
90
- export const example = defineTable("example", {
91
- id: integer("id").primaryKey({ autoIncrement: true }),
92
- isActive: integer("is_active", { mode: "boolean" }),
93
- createdAt: integer("created_at", { mode: "timestamp" }).default(
94
- sql`(strftime('%s','now'))`
95
- ),
96
- rating: real("rating"),
97
- status: text("status", { enum: ["active", "inactive"] as const }),
98
- name: text("name").notNull().default("Anonymous"),
99
- data: blob("data"),
100
- jsonField: blob("json_field", { mode: "json" }).$type<Data>(),
101
- bigCounter: blob("big_counter", { mode: "bigint" }),
102
- valueNumeric: numeric("value_numeric"),
103
- valueNumericNum: numeric("value_numeric_num", { mode: "number" }),
104
- valueNumericBig: numeric("value_numeric_big", { mode: "bigint" }),
105
- });
63
+ - [Getting Started](docs/getting-started.md)
64
+ - [Schema and Types](docs/schema-and-types.md)
65
+ - [CRUD Operations (SELECT)](docs/queries-select.md)
66
+ - [CRUD Operations (INSERT)](docs/crud-insert.md)
67
+ - [CRUD Operations (UPDATE)](docs/crud-update.md)
68
+ - [CRUD Operations (DELETE)](docs/crud-delete.md)
69
+ - [Migrations](docs/migrations.md)
70
+ - [Transactions](docs/transactions.md)
71
+ - [Relations](docs/relations.md)
106
72
 
107
- // Foreign key
108
- export const posts = defineTable("posts", {
109
- id: integer("id").primaryKey(),
110
- userId: integer("user_id")
111
- .references(() => users.id, { onDelete: "cascade" })
112
- .notNull(),
113
- });
114
- ```
73
+ ### Schema Definition
74
+
75
+ Define your tables and columns using a chainable, Drizzle-style API.
115
76
 
116
- ### More data types and modes
77
+ ```typescript
78
+ import { sqliteTable, text, integer, boolean } from "@type32/tauri-sqlite-orm";
117
79
 
118
- ```ts
119
- // JSON stored in TEXT with proper SQLite JSON function support
120
- const cfg = defineTable("cfg", {
121
- jsonText: text("json_text", { mode: "json" }).$type<{ foo: string }>(),
122
- tsMs: integer("ts_ms", { mode: "timestamp_ms" }),
123
- dataBuf: blob("data_buf", { mode: "buffer" }),
80
+ export const users = sqliteTable("users", {
81
+ id: integer("id").primaryKey().autoincrement(),
82
+ name: text("name").notNull(),
83
+ email: text("email").unique(),
84
+ isActive: boolean("is_active").default(true),
85
+ createdAt: integer("created_at", { mode: "timestamp" }).$defaultFn(
86
+ () => new Date()
87
+ ),
124
88
  });
125
89
  ```
126
90
 
127
- Tip: Prefer `text(name, { mode: 'json' })` over `blob(name, { mode: 'json' })` to use SQLite JSON functions.
91
+ ### CRUD Operations
128
92
 
129
- ### Migrations
130
-
131
- Tracked simple migrations are part of the ORM instance:
93
+ Perform `CREATE`, `READ`, `UPDATE`, and `DELETE` operations using a type-safe query builder.
132
94
 
133
- ```ts
134
- // one-off for specific tables
135
- await db.migrate([users, posts], { name: "init:users,posts" });
95
+ **SELECT**
136
96
 
137
- // or using configured schema
138
- await db.migrateConfigured({ name: "init:users,posts" });
139
- ```
97
+ ```typescript
98
+ import { eq, and } from "@type32/tauri-sqlite-orm";
140
99
 
141
- DDL emitted respects: primaryKey + autoIncrement, notNull, default(value or sql), references (with onDelete/onUpdate).
100
+ // Select all users
101
+ const allUsers = await db.select(users).execute();
142
102
 
143
- ### CRUD (Drizzle-like builders)
144
-
145
- ```ts
146
- // Insert
147
- await db.insert(users).values({ name: "Alice" }).execute();
148
- await db
149
- .insert(users)
150
- .values([{ name: "A" }, { name: "B" }])
151
- .execute();
103
+ // Select specific columns
104
+ const userNames = await db.select(users, ["name"]).execute();
152
105
 
153
- // Update
154
- import { eq } from "tauri-sqlite-orm";
155
- await db
156
- .update(users)
157
- .set({ email: "new@mail.com" })
158
- .where(eq(users.id, 1))
106
+ // Use WHERE conditions
107
+ const activeUsers = await db
108
+ .select(users)
109
+ .where(eq(users.isActive, true))
159
110
  .execute();
160
-
161
- // Delete
162
- await db.delete(users).where(eq(users.id, 2)).execute();
163
111
  ```
164
112
 
165
- ### Runtime defaults and onUpdate
113
+ **INSERT**
166
114
 
167
- ```ts
168
- import { defineTable, integer, text, increments } from "tauri-sqlite-orm";
115
+ ```typescript
116
+ // Insert a single user
117
+ const newUser = await db
118
+ .insert(users)
119
+ .values({ name: "Jane Doe", email: "jane.doe@example.com" });
169
120
 
170
- export const audit = defineTable("audit", {
171
- id: increments("id"),
172
- // Called on insert if value not provided
173
- createdAt: integer("created_at", { mode: "timestamp" }).$defaultFn(
174
- () => new Date()
175
- ),
176
- // Called on update when not explicitly set; if no default is provided, also used on insert
177
- updatedAt: integer("updated_at", { mode: "timestamp" }).$onUpdateFn(
178
- () => new Date()
179
- ),
180
- token: text("token").$default(() => crypto.randomUUID()),
181
- });
121
+ // Insert multiple users
122
+ await db.insert(users).values([
123
+ { name: "Alice", email: "alice@example.com" },
124
+ { name: "Bob", email: "bob@example.com" },
125
+ ]);
182
126
  ```
183
127
 
184
- ### Query API (relations)
128
+ **UPDATE**
185
129
 
186
- Auto-generated with `db.configure(tables, relations?)`:
130
+ ```typescript
131
+ import { eq } from "@type32/tauri-sqlite-orm";
187
132
 
188
- ```ts
189
- // Flat relations with join
190
- import { asc } from "tauri-sqlite-orm";
133
+ // Update a user's email
134
+ await db
135
+ .update(users)
136
+ .set({ email: "new.email@example.com" })
137
+ .where(eq(users.id, 1));
138
+ ```
191
139
 
192
- const usersWithPosts = await db.query.users.findMany({
193
- with: { posts: true },
194
- join: true,
195
- where: (users, { eq }) => eq(users.id, 1),
196
- orderBy: (users, { asc }) => [asc(users.id)],
197
- limit: 10,
198
- offset: 0,
199
- columns: { id: true, name: true },
200
- });
140
+ **DELETE**
201
141
 
202
- // Nested relations (batched loader)
203
- const nested = await db.query.users.findMany({
204
- with: {
205
- posts: {
206
- with: { comments: true },
207
- columns: ["id", "content"],
208
- },
209
- },
210
- });
142
+ ```typescript
143
+ import { eq } from "@type32/tauri-sqlite-orm";
211
144
 
212
- // First row helper
213
- const firstUser = await db.query.users.findFirst({
214
- where: (users, { eq }) => eq(users.id, 1),
215
- });
145
+ // Delete a user
146
+ await db.delete(users).where(eq(users.id, 1));
216
147
  ```
217
148
 
218
- Notes:
149
+ ### Migrations
219
150
 
220
- - `where` accepts SQL helpers (eq, lt, gte, like) or object map, or a callback `(table, ops) => SQL`.
221
- - `orderBy` accepts typed helpers or a callback `(table, { asc, desc }) => [...]`.
222
- - `columns` accepts string[] or object map of base table columns.
223
- - `join: true` only for one-level `with` (flat). Nested uses batched selects.
151
+ The ORM includes a simple migration system that automatically detects schema changes and applies them to the database.
224
152
 
225
- ### SQL helpers
153
+ ```typescript
154
+ // This will check if the schema has changed and run migrations if it has
155
+ await db.migrateIfDirty();
226
156
 
227
- ```ts
228
- import { eq, ne, gt, gte, lt, lte, like, asc, desc } from "tauri-sqlite-orm";
229
- db.query.posts.findMany({
230
- where: (posts, { eq }) => eq(posts.authorId, 1),
231
- orderBy: (posts, { asc }) => [asc(posts.id)],
232
- });
157
+ // You can also run migrations manually
158
+ await db.migrate();
233
159
  ```
234
160
 
235
- ### Nuxt + Tauri usage
236
-
237
- Initialize in a client plugin and ensure a single ORM instance is created:
238
-
239
- ```ts
240
- // plugins/orm.client.ts
241
- import { TauriORM } from "tauri-sqlite-orm";
242
- import { users, posts, usersRelations } from "@/lib/schema";
161
+ ### Transactions
243
162
 
244
- export default defineNuxtPlugin(async () => {
245
- const db = new TauriORM("sqlite:app.db");
246
- db.configure({ users, posts }, { users: usersRelations });
247
- await db.migrateConfigured({ name: "init:users,posts" });
163
+ Run multiple database operations within a transaction to ensure atomicity.
248
164
 
249
- return { provide: { db } };
165
+ ```typescript
166
+ await db.transaction(async (tx) => {
167
+ await tx.insert(users).values({ name: "From Transaction" });
168
+ await tx.delete(users).where(eq(users.id, 1));
250
169
  });
251
170
  ```
252
171