nanodb-orm 0.0.2 → 0.0.4

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.
Files changed (83) hide show
  1. package/README.md +211 -309
  2. package/dist/cli.d.ts +13 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +270 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/constants/index.d.ts +7 -54
  7. package/dist/constants/index.d.ts.map +1 -1
  8. package/dist/constants/index.js +9 -61
  9. package/dist/constants/index.js.map +1 -1
  10. package/dist/core/config.d.ts +3 -13
  11. package/dist/core/config.d.ts.map +1 -1
  12. package/dist/core/config.js +5 -27
  13. package/dist/core/config.js.map +1 -1
  14. package/dist/core/connection.d.ts +11 -20
  15. package/dist/core/connection.d.ts.map +1 -1
  16. package/dist/core/connection.js +35 -53
  17. package/dist/core/connection.js.map +1 -1
  18. package/dist/core/index.d.ts +2 -3
  19. package/dist/core/index.d.ts.map +1 -1
  20. package/dist/core/index.js +3 -18
  21. package/dist/core/index.js.map +1 -1
  22. package/dist/index.d.ts +40 -10
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +76 -31
  25. package/dist/index.js.map +1 -1
  26. package/dist/init.d.ts +79 -22
  27. package/dist/init.d.ts.map +1 -1
  28. package/dist/init.js +246 -48
  29. package/dist/init.js.map +1 -1
  30. package/dist/jest.setup.d.ts +4 -0
  31. package/dist/jest.setup.d.ts.map +1 -0
  32. package/dist/jest.setup.js +40 -0
  33. package/dist/jest.setup.js.map +1 -0
  34. package/dist/types/errors.d.ts +30 -12
  35. package/dist/types/errors.d.ts.map +1 -1
  36. package/dist/types/errors.js +98 -23
  37. package/dist/types/errors.js.map +1 -1
  38. package/dist/types/index.d.ts +130 -3
  39. package/dist/types/index.d.ts.map +1 -1
  40. package/dist/types/index.js +2 -3
  41. package/dist/types/index.js.map +1 -1
  42. package/dist/utils/error-handler.d.ts +11 -0
  43. package/dist/utils/error-handler.d.ts.map +1 -0
  44. package/dist/utils/error-handler.js +36 -0
  45. package/dist/utils/error-handler.js.map +1 -0
  46. package/dist/utils/index.d.ts +1 -1
  47. package/dist/utils/index.d.ts.map +1 -1
  48. package/dist/utils/index.js +4 -2
  49. package/dist/utils/index.js.map +1 -1
  50. package/dist/utils/logger.d.ts +6 -25
  51. package/dist/utils/logger.d.ts.map +1 -1
  52. package/dist/utils/logger.js +20 -38
  53. package/dist/utils/logger.js.map +1 -1
  54. package/dist/utils/migrations.d.ts +16 -90
  55. package/dist/utils/migrations.d.ts.map +1 -1
  56. package/dist/utils/migrations.js +222 -412
  57. package/dist/utils/migrations.js.map +1 -1
  58. package/dist/utils/schema-introspection.d.ts +30 -173
  59. package/dist/utils/schema-introspection.d.ts.map +1 -1
  60. package/dist/utils/schema-introspection.js +129 -460
  61. package/dist/utils/schema-introspection.js.map +1 -1
  62. package/dist/utils/seeds.d.ts +15 -48
  63. package/dist/utils/seeds.d.ts.map +1 -1
  64. package/dist/utils/seeds.js +101 -185
  65. package/dist/utils/seeds.js.map +1 -1
  66. package/dist/utils/sync.d.ts +16 -54
  67. package/dist/utils/sync.d.ts.map +1 -1
  68. package/dist/utils/sync.js +71 -173
  69. package/dist/utils/sync.js.map +1 -1
  70. package/dist/utils/transactions.d.ts +16 -0
  71. package/dist/utils/transactions.d.ts.map +1 -0
  72. package/dist/utils/transactions.js +44 -0
  73. package/dist/utils/transactions.js.map +1 -0
  74. package/package.json +29 -10
  75. package/dist/example.d.ts +0 -67
  76. package/dist/example.d.ts.map +0 -1
  77. package/dist/example.js +0 -86
  78. package/dist/example.js.map +0 -1
  79. package/dist/types/types.d.ts +0 -30
  80. package/dist/types/types.d.ts.map +0 -1
  81. package/dist/types/types.js +0 -6
  82. package/dist/types/types.js.map +0 -1
  83. package/llm.txt +0 -268
package/README.md CHANGED
@@ -1,434 +1,336 @@
1
1
  # nanodb-orm
2
2
 
3
- A generic, flexible database package built on top of Drizzle ORM with automatic migrations, schema introspection, and support for both local SQLite and remote Turso databases.
3
+ A lightweight, schema-agnostic ORM wrapper for Drizzle ORM with automatic migrations, schema introspection, CLI tools, and support for SQLite/Turso databases.
4
4
 
5
5
  ## Features
6
6
 
7
- - 🚀 **Auto-Migrations**: Automatically creates and updates database schemas from Drizzle table definitions
8
- - 🔍 **Schema Introspection**: Comprehensive schema analysis and validation
9
- - 🌐 **Multi-Database Support**: Works with local SQLite and remote Turso databases
10
- - 📦 **NPM Package Ready**: Designed to be used as a standalone npm package
11
- - 🛡️ **Type Safe**: Full TypeScript support with proper type inference
12
- - ⚙️ **Configurable**: Flexible migration and seeding options
13
- - 🧪 **Test Ready**: Built-in testing utilities and isolation
7
+ - **Auto-Migrations** Automatically creates and updates database schemas from Drizzle tables
8
+ - **Schema Introspection** Comprehensive schema analysis and validation
9
+ - **Multi-Database** Works with local SQLite and remote Turso databases
10
+ - **Transactions** Full transaction support with automatic rollback
11
+ - **CLI Tools** Built-in commands including Drizzle Studio integration
12
+ - **Type Safe** Full TypeScript support with proper type inference
13
+ - **Plugin System** Extensible with hooks for audit, validation, transformations
14
+ - **Minimal** — ~1K lines of code, zero bloat
14
15
 
15
16
  ## Installation
16
17
 
17
18
  ```bash
18
19
  npm install nanodb-orm
20
+
21
+ # For Drizzle Studio support (optional)
22
+ npm install drizzle-kit --save-dev
19
23
  ```
20
24
 
21
- ## Quick Start
25
+ ## CLI
22
26
 
23
- ### 1. Define Your Models with Drizzle
27
+ nanodb-orm includes a CLI for common database operations:
24
28
 
25
- Create your Drizzle table definitions (e.g., `models/users.ts`):
29
+ ```bash
30
+ # Launch Drizzle Studio (visual database browser)
31
+ npx nanodb studio
26
32
 
27
- ```typescript
28
- // models/users.ts
29
- import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
33
+ # With custom port
34
+ npx nanodb studio --port 3000
30
35
 
31
- export const usersTable = sqliteTable('users', {
32
- id: integer('id').primaryKey({ autoIncrement: true }),
33
- name: text('name').notNull(),
34
- age: integer('age').notNull(),
35
- email: text('email').unique().notNull(),
36
- });
36
+ # With specific database file
37
+ npx nanodb studio --db ./data/myapp.db
37
38
 
38
- export type InsertUser = typeof usersTable.$inferInsert;
39
- export type SelectUser = typeof usersTable.$inferSelect;
39
+ # Other commands
40
+ npx nanodb setup # Initialize schema and seed data
41
+ npx nanodb reset # Drop all tables and recreate
42
+ npx nanodb status # Show database health and stats
43
+ npx nanodb validate # Validate schema against database
44
+ npx nanodb help # Show all commands
40
45
  ```
41
46
 
42
- ```typescript
43
- // models/posts.ts
44
- import { sql } from 'drizzle-orm';
45
- import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
46
- import { usersTable } from './users';
47
+ ### Drizzle Studio
47
48
 
48
- export const postsTable = sqliteTable('posts', {
49
- id: integer('id').primaryKey({ autoIncrement: true }),
50
- title: text('title').notNull(),
51
- content: text('content').notNull(),
52
- userId: integer('user_id')
53
- .notNull()
54
- .references(() => usersTable.id, { onDelete: 'cascade' }),
55
- createdAt: text('created_at')
56
- .default(sql`(datetime('now'))`)
57
- .notNull(),
58
- updatedAt: text('updated_at').$onUpdate(() => new Date().toISOString()),
59
- });
49
+ Launch a visual database browser at `https://local.drizzle.studio`:
60
50
 
61
- export type InsertPost = typeof postsTable.$inferInsert;
62
- export type SelectPost = typeof postsTable.$inferSelect;
51
+ ```bash
52
+ npx nanodb studio
63
53
  ```
64
54
 
55
+ ![Drizzle Studio](https://orm.drizzle.team/images/drizzle-studio.png)
56
+
57
+ ## Quick Start
58
+
59
+ ### 1. Define Your Schema
60
+
65
61
  ```typescript
66
- // models/categories.ts
67
- import { sql } from 'drizzle-orm';
68
- import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
62
+ import { table, integer, text } from 'nanodb-orm';
69
63
 
70
- export const categoriesTable = sqliteTable('categories', {
64
+ const users = table('users', {
71
65
  id: integer('id').primaryKey({ autoIncrement: true }),
72
66
  name: text('name').notNull(),
73
- description: text('description'),
74
- color: text('color').notNull().default('#000000'),
75
- isActive: integer('is_active').notNull().default(1),
76
- createdAt: text('created_at')
77
- .default(sql`(datetime('now'))`)
78
- .notNull(),
67
+ email: text('email').unique().notNull(),
68
+ age: integer('age'),
79
69
  });
80
70
 
81
- export type InsertCategory = typeof categoriesTable.$inferInsert;
82
- export type SelectCategory = typeof categoriesTable.$inferSelect;
83
- ```
71
+ const posts = table('posts', {
72
+ id: integer('id').primaryKey({ autoIncrement: true }),
73
+ title: text('title').notNull(),
74
+ userId: integer('userId').notNull(),
75
+ });
84
76
 
85
- ```typescript
86
- // models/index.ts
87
- export * from './users';
88
- export * from './posts';
89
- export * from './categories';
90
-
91
- // Import tables for aggregation
92
- import { usersTable } from './users';
93
- import { postsTable } from './posts';
94
- import { categoriesTable } from './categories';
95
-
96
- // Export aggregated tables for nanodb-orm
97
- export const tables = {
98
- users: usersTable,
99
- posts: postsTable,
100
- categories: categoriesTable,
101
- } as const;
77
+ const tables = { users, posts };
102
78
  ```
103
79
 
104
- ### 2. Initialize and Setup Database
80
+ ### 2. Create Database
105
81
 
106
82
  ```typescript
107
- import { initializeDatabase, DatabaseSync } from 'nanodb-orm';
108
- import { tables } from './models';
83
+ import { createDatabase } from 'nanodb-orm';
109
84
 
110
- // Initialize the database package with your Drizzle tables
111
- initializeDatabase({
85
+ // One line: creates tables, runs migrations, seeds data, returns db
86
+ const db = await createDatabase({
112
87
  tables,
113
88
  seedData: {
114
- users: [
115
- { name: 'John Doe', age: 30, email: 'john@example.com' },
116
- { name: 'Jane Smith', age: 25, email: 'jane@example.com' }
117
- ],
118
- posts: [
119
- { title: 'Welcome Post', content: 'This is my first post!', userId: 1 },
120
- { title: 'Getting Started', content: 'Here are some tips...', userId: 2 }
121
- ],
122
- categories: [
123
- { name: 'Technology', description: 'Tech-related posts', color: '#3B82F6' },
124
- { name: 'Lifestyle', description: 'Life and personal posts', color: '#10B981' }
125
- ]
126
- }
89
+ users: [{ name: 'Alice', email: 'alice@example.com', age: 28 }],
90
+ },
127
91
  });
128
92
 
129
- // Setup database (creates tables, runs migrations, seeds data)
130
- await DatabaseSync.setup();
93
+ // Store db and use it everywhere - no need for getInstance() or getDb()
94
+ export { db };
131
95
  ```
132
96
 
133
- ### 3. Working with Drizzle Tables
134
-
135
- nanodb-orm works seamlessly with Drizzle ORM table definitions. Here are the key Drizzle column types and methods:
136
-
137
- #### Drizzle Column Types
138
- - `integer()` - Integer numbers
139
- - `text()` - Text strings
140
- - `real()` - Floating point numbers
141
- - `blob()` - Binary data
97
+ ### 3. Query with Type Safety
142
98
 
143
- #### Drizzle Column Methods
144
- - `.primaryKey({ autoIncrement: true })` - Primary key with auto-increment
145
- - `.notNull()` - NOT NULL constraint
146
- - `.unique()` - UNIQUE constraint
147
- - `.default(value)` - Default value
148
- - `.references(table.column)` - Foreign key reference
149
-
150
- #### Example Drizzle Column Definitions
151
99
  ```typescript
152
- // Primary key with auto-increment
153
- id: integer('id').primaryKey({ autoIncrement: true })
154
-
155
- // Required text field
156
- name: text('name').notNull()
157
-
158
- // Optional text field with default
159
- color: text('color').notNull().default('#000000')
100
+ import { eq, gte } from 'nanodb-orm';
160
101
 
161
- // Unique email field
162
- email: text('email').unique().notNull()
102
+ // SELECT
103
+ const allUsers = await db.select().from(users);
104
+ const adults = await db.select().from(users).where(gte(users.age, 18));
163
105
 
164
- // Boolean field (stored as integer)
165
- isActive: integer('is_active').notNull().default(1)
106
+ // INSERT
107
+ await db.insert(users).values({ name: 'Bob', email: 'bob@example.com' });
166
108
 
167
- // Timestamp field with SQL function
168
- createdAt: text('created_at')
169
- .default(sql`(datetime('now'))`)
170
- .notNull()
109
+ // UPDATE
110
+ await db.update(users).set({ name: 'Robert' }).where(eq(users.email, 'bob@example.com'));
171
111
 
172
- // Foreign key reference
173
- userId: integer('user_id')
174
- .notNull()
175
- .references(() => usersTable.id, { onDelete: 'cascade' })
112
+ // DELETE
113
+ await db.delete(users).where(eq(users.email, 'bob@example.com'));
176
114
  ```
177
115
 
178
116
  ## API Reference
179
117
 
180
- ### `initializeDatabase(schemaData: SchemaData)`
118
+ ### `createDatabase(config)`
181
119
 
182
- Initializes the database package with your schema data.
120
+ Create and initialize database. Returns `db` with all utilities attached.
183
121
 
184
122
  ```typescript
185
- interface SchemaData {
186
- tables: Record<string, any>; // Your Drizzle table definitions
187
- seedData?: Record<string, any[]>; // Optional seed data
188
- migrationConfig?: MigrationConfig; // Optional migration configuration
189
- }
190
-
191
- interface MigrationConfig {
192
- preserveData?: boolean; // Preserve existing data (default: true)
193
- autoMigrate?: boolean; // Enable auto-migrations (default: true)
194
- dropTables?: boolean; // Allow dropping tables (default: false)
195
- }
123
+ const db = await createDatabase({
124
+ tables: { users, posts },
125
+ seedData: { users: [...] },
126
+ migrationConfig: {
127
+ preserveData: true, // default: true
128
+ autoMigrate: true, // default: true
129
+ dropTables: false, // default: false
130
+ },
131
+ plugins: [auditPlugin, validationPlugin], // optional
132
+ });
196
133
  ```
197
134
 
198
- ### `DatabaseSync`
199
-
200
- Main database synchronization class.
135
+ ### Database Operations (from `db`)
201
136
 
202
137
  ```typescript
203
- // Setup database (create tables, migrate, seed)
204
- await DatabaseSync.setup();
205
-
206
- // Reset database (drop all tables and recreate)
207
- await DatabaseSync.reset();
208
-
209
- // Check if database is ready
210
- const isReady = await DatabaseSync.isReady();
138
+ // Health & Status
139
+ await db.healthCheck(); // { healthy, tables, totalRecords, ... }
140
+ await db.isReady(); // true/false
141
+ await db.sync(); // Sync with Turso (if remote)
142
+
143
+ // Reset & Seed
144
+ await db.reset(); // Drop all, recreate, reseed
145
+ await db.seed(); // Re-seed data
146
+ await db.clearData(); // Delete all data (keep tables)
211
147
  ```
212
148
 
213
- ### `SchemaIntrospection`
214
-
215
- Comprehensive schema analysis utilities.
149
+ ### Schema Introspection (from `db.schema`)
216
150
 
217
151
  ```typescript
218
- // Get all table names
219
- const tableNames = SchemaIntrospection.getAllTableNames();
220
-
221
- // Get table information
222
- const tableInfo = SchemaIntrospection.getTableInfo('users');
152
+ db.schema.tables(); // ['users', 'posts']
153
+ db.schema.getTable('users'); // { columns, primaryKey, indexes }
154
+ db.schema.getColumns('users'); // ['id', 'name', 'email']
155
+ await db.schema.validate(); // { isValid, missingTables, ... }
156
+ db.schema.stats(); // Full schema statistics
157
+ db.schema.relationships(); // Foreign key relationships
158
+ ```
223
159
 
224
- // Get schema statistics
225
- const stats = SchemaIntrospection.getSchemaStats();
160
+ ### Migrations (from `db.migrations`)
226
161
 
227
- // Validate schema
228
- const validation = await SchemaIntrospection.validateSchema();
162
+ ```typescript
163
+ await db.migrations.run(); // Run pending migrations
164
+ await db.migrations.validate(); // Validate schema vs DB
165
+ await db.migrations.checkTables(); // { users: true, posts: true }
229
166
  ```
230
167
 
231
- ### `DatabaseMigrations`
168
+ ### `transaction(fn)`
232
169
 
233
- Migration management utilities.
170
+ Execute operations atomically.
234
171
 
235
172
  ```typescript
236
- // Initialize schema
237
- await DatabaseMigrations.initializeSchema();
173
+ import { transaction, sql } from 'nanodb-orm';
238
174
 
239
- // Check table existence
240
- const existence = await DatabaseMigrations.checkTableExistence();
175
+ const result = await transaction(async (tx) => {
176
+ await tx.run(sql`INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com')`);
177
+ await tx.run(sql`INSERT INTO posts (title, userId) VALUES ('Hello', 1)`);
178
+ return { created: true };
179
+ });
241
180
 
242
- // Validate schema
243
- const validation = await DatabaseMigrations.validateSchema();
181
+ if (result.success) {
182
+ console.log(result.result);
183
+ } else {
184
+ console.log('Rolled back:', result.error?.message);
185
+ }
244
186
  ```
245
187
 
246
- ### `DatabaseSeeds`
188
+ ### `parseDbError(error, context)`
247
189
 
248
- Database seeding utilities.
190
+ Parse SQLite errors into user-friendly messages.
249
191
 
250
192
  ```typescript
251
- // Seed database
252
- await DatabaseSeeds.seedDatabase();
253
-
254
- // Check if database has data
255
- const hasData = await DatabaseSeeds.hasData();
193
+ import { parseDbError } from 'nanodb-orm';
256
194
 
257
- // Clear all data
258
- await DatabaseSeeds.clearAllData();
195
+ try {
196
+ await db.run('INSERT INTO users ...');
197
+ } catch (error) {
198
+ const parsed = parseDbError(error, { table: 'users', operation: 'insert' });
199
+ console.log(parsed.message); // "Column 'email' does not exist"
200
+ }
259
201
  ```
260
202
 
261
- ## Configuration
203
+ ## Plugins
262
204
 
263
- ### Environment Variables
264
-
265
- ```bash
266
- # Turso Database (optional)
267
- TURSO_CONNECTION_URL=libsql://your-database.turso.io
268
- TURSO_AUTH_TOKEN=your-auth-token
205
+ Extend nanodb-orm with custom hooks that run automatically on database operations.
269
206
 
270
- # Force local database (for testing)
271
- FORCE_LOCAL_DB=true
272
- NODE_ENV=test
273
- ```
274
-
275
- ### Migration Configuration
207
+ ### Plugin Interface
276
208
 
277
209
  ```typescript
278
- const migrationConfig = {
279
- preserveData: true, // Always try to preserve existing data
280
- autoMigrate: true, // Automatically handle schema changes
281
- dropTables: false // Don't drop tables by default
210
+ import { NanoPlugin } from 'nanodb-orm';
211
+
212
+ const myPlugin: NanoPlugin = {
213
+ name: 'my-plugin',
214
+
215
+ // Lifecycle
216
+ install: (db) => db, // Modify db instance
217
+ onReady: (db) => {}, // Called after createDatabase
218
+ onError: (err, op, table) => {}, // Called on hook errors
219
+
220
+ // Auto hooks (run automatically)
221
+ beforeInsert: (table, data) => data, // Transform data before insert
222
+ afterInsert: (table, data, result) => {},
223
+ beforeUpdate: (table, data) => data, // Transform data before update
224
+ afterUpdate: (table, data, result) => {},
225
+ beforeDelete: (table, condition) => condition,
226
+ afterDelete: (table, condition, result) => {},
227
+
228
+ // Query hooks (also auto-triggered)
229
+ beforeQuery: (table, fields) => fields,
230
+ afterQuery: (table, fields, result) => {},
282
231
  };
283
-
284
- initializeDatabase({
285
- tables,
286
- migrationConfig
287
- });
288
232
  ```
289
233
 
290
- ## Usage Examples
234
+ ### Example Plugins
291
235
 
292
- ### Basic Setup
236
+ These are **example plugins you can create** - nanodb-orm provides the plugin system, you build the plugins:
293
237
 
294
238
  ```typescript
295
- import { initializeDatabase, DatabaseSync } from 'nanodb-orm';
296
- import { usersTable, postsTable } from './models';
297
-
298
- const tables = {
299
- users: usersTable,
300
- posts: postsTable
239
+ // Example: Audit logging with timing
240
+ const timers = new Map<string, number>();
241
+ const auditPlugin: NanoPlugin = {
242
+ name: 'audit',
243
+ beforeInsert: (table) => { timers.set('op', performance.now()); console.log(`INSERT ${table}`); },
244
+ afterInsert: () => { console.log(` ↳ ${(performance.now() - timers.get('op')!).toFixed(1)}ms`); },
245
+ beforeQuery: (table) => { timers.set('op', performance.now()); console.log(`SELECT ${table}`); },
246
+ afterQuery: (t, _, rows) => { console.log(` ↳ ${rows.length} rows in ${(performance.now() - timers.get('op')!).toFixed(1)}ms`); },
301
247
  };
302
248
 
303
- initializeDatabase({ tables });
304
- await DatabaseSync.setup();
305
- ```
306
-
307
- ### With Seed Data
308
-
309
- ```typescript
310
- const seedData = {
311
- users: [
312
- { name: 'Alice', age: 25, email: 'alice@example.com' },
313
- { name: 'Bob', age: 30, email: 'bob@example.com' }
314
- ],
315
- posts: [
316
- { title: 'Hello World', content: 'My first post', userId: 1 },
317
- { title: 'Second Post', content: 'Another post', userId: 2 }
318
- ]
249
+ // Auto-generate slugs
250
+ const slugPlugin: NanoPlugin = {
251
+ name: 'slug',
252
+ beforeInsert: (table, data) => {
253
+ if (table === 'posts' && data.title && !data.slug) {
254
+ return { ...data, slug: data.title.toLowerCase().replace(/\s+/g, '-') };
255
+ }
256
+ return data;
257
+ },
319
258
  };
320
259
 
321
- initializeDatabase({ tables, seedData });
322
- await DatabaseSync.setup();
323
- ```
324
-
325
- ### Custom Migration Config
326
-
327
- ```typescript
328
- const migrationConfig = {
329
- preserveData: false, // Allow data loss for development
330
- autoMigrate: true, // Enable auto-migrations
331
- dropTables: true // Allow dropping tables
260
+ // Validation
261
+ const validationPlugin: NanoPlugin = {
262
+ name: 'validation',
263
+ beforeInsert: (table, data) => {
264
+ if (table === 'users' && !data.email?.includes('@')) {
265
+ throw new Error('Invalid email format');
266
+ }
267
+ return data;
268
+ },
332
269
  };
333
270
 
334
- initializeDatabase({
335
- tables,
336
- migrationConfig
271
+ // Use plugins
272
+ const db = await createDatabase({
273
+ tables,
274
+ plugins: [auditPlugin, slugPlugin, validationPlugin],
337
275
  });
338
- ```
339
276
 
340
- ### Schema Introspection
277
+ // Hooks run automatically
278
+ await db.insert(posts).values({ title: 'My Post' }); // slug auto-generated
279
+ await db.insert(users).values({ email: 'invalid' }); // throws error
341
280
 
342
- ```typescript
343
- import { SchemaIntrospection } from 'nanodb-orm';
344
-
345
- // Get comprehensive schema information
346
- const schemaInfo = SchemaIntrospection.getSchemaStats();
347
- console.log('Total tables:', schemaInfo.totalTables);
348
- console.log('Table details:', schemaInfo.tableDetails);
349
-
350
- // Validate schema integrity
351
- const validation = await SchemaIntrospection.validateSchema();
352
- if (!validation.isValid) {
353
- console.log('Schema issues:', validation.errors);
354
- }
281
+ // Check loaded plugins
282
+ db.plugins.list(); // ['audit', 'slug', 'validation']
355
283
  ```
356
284
 
357
- ## Testing
358
-
359
- The package includes built-in testing utilities:
285
+ ## Configuration
360
286
 
361
- ```typescript
362
- import { DatabaseSync } from 'nanodb-orm';
287
+ ### Environment Variables
363
288
 
364
- describe('My Tests', () => {
365
- beforeEach(async () => {
366
- // Reset database for each test
367
- await DatabaseSync.reset();
368
- });
289
+ ```bash
290
+ # Remote Turso database
291
+ TURSO_CONNECTION_URL=libsql://your-db.turso.io
292
+ TURSO_AUTH_TOKEN=your-token
369
293
 
370
- test('should work with clean database', async () => {
371
- // Your test code here
372
- });
373
- });
294
+ # Force local SQLite (for testing)
295
+ FORCE_LOCAL_DB=true
374
296
  ```
375
297
 
376
- ## Database Support
377
-
378
- ### Local SQLite
379
- - Automatically used when Turso credentials are not available
380
- - Perfect for development and testing
381
- - File-based storage
298
+ ### Database Selection
382
299
 
383
- ### Remote Turso
384
- - Cloud-hosted SQLite database
385
- - Requires `TURSO_CONNECTION_URL` and `TURSO_AUTH_TOKEN`
386
- - Production-ready with global replication
300
+ - **Turso** — Used when `TURSO_CONNECTION_URL` and `TURSO_AUTH_TOKEN` are set
301
+ - **Local SQLite** — Fallback when Turso credentials are missing
302
+ - **Test Mode** — Isolated `test.db` when `NODE_ENV=test`
387
303
 
388
304
  ## Error Handling
389
305
 
390
- The package provides comprehensive error handling:
306
+ Errors are automatically parsed into user-friendly messages:
391
307
 
392
308
  ```typescript
393
- import { DatabaseError } from 'nanodb-orm';
309
+ import { DatabaseError, SchemaError, SeedError, parseDbError } from 'nanodb-orm';
394
310
 
395
311
  try {
396
312
  await DatabaseSync.setup();
397
313
  } catch (error) {
398
314
  if (error instanceof DatabaseError) {
399
- console.log('Database error:', error.message);
400
- console.log('Operation:', error.operation);
315
+ console.log(error.message); // User-friendly message
316
+ console.log(error.operation); // 'seed', 'migration', etc.
317
+ console.log(error.table); // Table name if applicable
318
+ console.log(error.detail); // Additional context
401
319
  }
402
320
  }
403
321
  ```
404
322
 
405
- ## Contributing
323
+ Error output is clean and actionable:
406
324
 
407
- 1. Fork the repository
408
- 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
409
- 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
410
- 4. Push to the branch (`git push origin feature/amazing-feature`)
411
- 5. Open a Pull Request
325
+ ```
326
+ ┌─ nanodb-orm error ─────────────────────────────
327
+ Column "email" does not exist
328
+ Table: users
329
+ Operation: seed
330
+ │ Detail: Row data: {"name":"Alice","email":"alice@example.com"}
331
+ └────────────────────────────────────────────────
332
+ ```
412
333
 
413
334
  ## License
414
335
 
415
336
  MIT © Damilola Alao
416
-
417
- ## Changelog
418
-
419
- ### 0.0.2
420
- - **Enhanced Documentation**: Added comprehensive Drizzle ORM integration examples
421
- - **Real Model Examples**: Updated documentation with actual Drizzle table definitions
422
- - **Schema Validation Fix**: Fixed table existence validation logic for proper health checks
423
- - **LLM Documentation**: Added detailed `llm.txt` file for AI/LLM integration
424
- - **Column Types Guide**: Added complete Drizzle column types and methods documentation
425
- - **Foreign Key Support**: Documented foreign key relationships and cascade deletes
426
- - **Type Safety**: Enhanced TypeScript integration examples with Drizzle's type inference
427
-
428
- ### 0.0.1
429
- - Initial release
430
- - Auto-migration system
431
- - Schema introspection
432
- - Multi-database support
433
- - TypeScript support
434
- - Testing utilities
package/dist/cli.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * nanodb-orm CLI
4
+ *
5
+ * Commands:
6
+ * studio - Launch Drizzle Studio (visual database browser)
7
+ * setup - Initialize database schema and seed data
8
+ * reset - Drop all tables and recreate
9
+ * status - Show database health and stats
10
+ * validate - Validate schema against database
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG"}