@doviui/dev-db 0.1.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/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2025 Calvin Kimani
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,532 @@
1
+ # dev-db
2
+
3
+ **TypeScript-first mock database generator for rapid application development**
4
+
5
+ dev-db eliminates the friction of setting up databases during development. Define your data model with a type-safe schema, generate realistic mock data instantly, and iterate faster without database infrastructure overhead.
6
+
7
+ ## Why dev-db?
8
+
9
+ **For Frontend Developers**: Build and test UI components with realistic data without waiting for backend APIs. Generate hundreds of records in seconds and work independently.
10
+
11
+ **For Backend Developers**: Prototype schemas, test business logic, and validate data models before committing to a database. Catch schema errors early with built-in validation.
12
+
13
+ **For Teams**: Share reproducible datasets across development, testing, and CI/CD environments using seeds. Onboard new developers instantly with pre-generated data.
14
+
15
+ ## Key Features
16
+
17
+ - **Type-Safe Schema Definition** - Fluent TypeScript API with full IntelliSense support
18
+ - **Automatic Relationship Resolution** - Foreign keys handled intelligently with topological sorting
19
+ - **Production-Quality Mock Data** - Powered by Faker.js for realistic, diverse datasets
20
+ - **Built-In Validation** - Detect circular dependencies, missing tables, and constraint conflicts before generation
21
+ - **Reproducible Datasets** - Seed-based generation for consistent data across environments
22
+ - **Zero Configuration** - Works out of the box, no database setup required
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ bun add @doviui/dev-db
28
+ # or
29
+ npm install @doviui/dev-db
30
+ # or
31
+ yarn add @doviui/dev-db
32
+ # or
33
+ pnpm add @doviui/dev-db
34
+ ```
35
+
36
+ ## Quick Start
37
+
38
+ ### Step 1: Define Your Schema
39
+
40
+ Create schema files using the fluent TypeScript API:
41
+
42
+ ```typescript
43
+ // schemas/user.schema.ts
44
+ import { t } from '@doviui/dev-db'
45
+
46
+ export default {
47
+ User: {
48
+ $count: 100, // Generate 100 users
49
+
50
+ id: t.bigserial().primaryKey(),
51
+ username: t.varchar(50).unique().notNull().generate('internet.userName'),
52
+ email: t.varchar(255).unique().notNull().generate('internet.email'),
53
+ full_name: t.text().generate('person.fullName'),
54
+ age: t.integer().min(18).max(90),
55
+ is_active: t.boolean().default(true),
56
+ created_at: t.timestamptz().default('now')
57
+ }
58
+ }
59
+ ```
60
+
61
+ ```typescript
62
+ // schemas/post.schema.ts
63
+ import { t } from '@doviui/dev-db'
64
+
65
+ export default {
66
+ Post: {
67
+ $count: 500, // Generate 500 posts
68
+
69
+ id: t.bigserial().primaryKey(),
70
+ user_id: t.foreignKey('User', 'id').notNull(),
71
+ title: t.varchar(200).generate('lorem.sentence'),
72
+ content: t.text().generate('lorem.paragraphs'),
73
+ status: t.varchar(20).enum(['draft', 'published', 'archived']).default('draft'),
74
+ view_count: t.integer().default(0),
75
+ created_at: t.timestamptz().default('now')
76
+ }
77
+ }
78
+ ```
79
+
80
+ ### Step 2: Generate Your Data
81
+
82
+ #### Using the CLI directly
83
+
84
+ Run the CLI to generate JSON files:
85
+
86
+ ```bash
87
+ # Generate from a directory of schemas
88
+ bunx @doviui/dev-db generate ./schemas -o ./mock-data
89
+
90
+ # Generate from a single file
91
+ bunx @doviui/dev-db generate ./schemas/user.schema.ts -o ./data
92
+
93
+ # Use a seed for reproducible data
94
+ bunx @doviui/dev-db generate ./schemas --seed 42
95
+ ```
96
+
97
+ #### Adding to package.json scripts
98
+
99
+ Add generation to your project's scripts:
100
+
101
+ ```json
102
+ {
103
+ "scripts": {
104
+ "generate:data": "bunx @doviui/dev-db generate ./schemas -o ./mock-data",
105
+ "generate:data:seed": "bunx @doviui/dev-db generate ./schemas -o ./mock-data --seed 42"
106
+ }
107
+ }
108
+ ```
109
+
110
+ Then run with:
111
+
112
+ ```bash
113
+ bun run generate:data
114
+ # or with a seed
115
+ bun run generate:data:seed
116
+ ```
117
+
118
+ ### Step 3: Consume Your Data
119
+
120
+ Import the generated JSON and use it in your application:
121
+
122
+ ```typescript
123
+ // server.ts
124
+ import users from './mock-data/User.json'
125
+ import posts from './mock-data/Post.json'
126
+
127
+ // Simple query helpers
128
+ function getUserById(id: number) {
129
+ return users.find(u => u.id === id)
130
+ }
131
+
132
+ function getPostsByUserId(userId: number) {
133
+ return posts.filter(p => p.user_id === userId)
134
+ }
135
+
136
+ // Use in your API
137
+ app.get('/users/:id', (req, res) => {
138
+ const user = getUserById(parseInt(req.params.id))
139
+ if (!user) return res.status(404).json({ error: 'User not found' })
140
+
141
+ const userPosts = getPostsByUserId(user.id)
142
+ res.json({ ...user, posts: userPosts })
143
+ })
144
+ ```
145
+
146
+ ## API Reference
147
+
148
+ ### Data Types
149
+
150
+ dev-db supports a comprehensive set of SQL-inspired data types:
151
+
152
+ #### Numeric Types
153
+ ```typescript
154
+ t.bigint() // Big integer
155
+ t.bigserial() // Auto-incrementing big integer
156
+ t.integer() // Standard integer
157
+ t.smallint() // Small integer
158
+ t.serial() // Auto-incrementing integer
159
+ t.decimal(10, 2) // Decimal with precision and scale
160
+ t.numeric(10, 2) // Alias for decimal
161
+ t.real() // Floating point
162
+ t.double() // Double precision float
163
+ ```
164
+
165
+ #### String Types
166
+ ```typescript
167
+ t.varchar(255) // Variable-length string
168
+ t.char(10) // Fixed-length string
169
+ t.text() // Unlimited text
170
+ ```
171
+
172
+ #### Date/Time Types
173
+ ```typescript
174
+ t.date() // Date only
175
+ t.time() // Time only
176
+ t.timestamp() // Date and time
177
+ t.timestamptz() // Date and time with timezone
178
+ ```
179
+
180
+ #### Other Types
181
+ ```typescript
182
+ t.boolean() // True/false
183
+ t.uuid() // UUID v4
184
+ t.json() // JSON object
185
+ t.jsonb() // JSON binary
186
+ ```
187
+
188
+ #### Relationships
189
+ ```typescript
190
+ t.foreignKey('TableName', 'column') // Foreign key reference
191
+ ```
192
+
193
+ ### Field Modifiers
194
+
195
+ Chain modifiers to configure field behavior and constraints:
196
+
197
+ ```typescript
198
+ // Constraints
199
+ .primaryKey() // Mark as primary key
200
+ .unique() // Enforce uniqueness
201
+ .notNull() // Cannot be null
202
+ .nullable() // Can be null (default)
203
+
204
+ // Defaults
205
+ .default(value) // Set default value
206
+ .default('now') // Special: current timestamp
207
+
208
+ // Ranges (for numeric types)
209
+ .min(18) // Minimum value
210
+ .max(90) // Maximum value
211
+
212
+ // Enums
213
+ .enum(['draft', 'published', 'archived'])
214
+
215
+ // Custom generation
216
+ .generate('internet.email') // Use Faker.js method
217
+ .generate(() => Math.random() * 100) // Custom function
218
+ ```
219
+
220
+ ## Advanced Usage
221
+
222
+ ### Multi-Table Schemas
223
+
224
+ Define multiple related tables in a single file for better organization:
225
+
226
+ ```typescript
227
+ // schemas/social.schema.ts
228
+ import { t } from '@doviui/dev-db'
229
+
230
+ export default {
231
+ User: {
232
+ $count: 100,
233
+ id: t.bigserial().primaryKey(),
234
+ username: t.varchar(50).unique()
235
+ },
236
+
237
+ Post: {
238
+ $count: 500,
239
+ id: t.bigserial().primaryKey(),
240
+ user_id: t.foreignKey('User', 'id'),
241
+ title: t.varchar(200)
242
+ },
243
+
244
+ Comment: {
245
+ $count: 2000,
246
+ id: t.uuid().primaryKey(),
247
+ post_id: t.foreignKey('Post', 'id'),
248
+ user_id: t.foreignKey('User', 'id'),
249
+ content: t.text()
250
+ }
251
+ }
252
+ ```
253
+
254
+ ### Schema Validation
255
+
256
+ dev-db validates schemas before generation to catch errors early:
257
+
258
+ ```typescript
259
+ // ❌ This will fail validation
260
+ export default {
261
+ Post: {
262
+ id: t.bigserial().primaryKey(),
263
+ user_id: t.foreignKey('User', 'id') // Error: User table doesn't exist!
264
+ }
265
+ }
266
+ ```
267
+
268
+ **Output:**
269
+ ```
270
+ 🔍 Validating schemas...
271
+
272
+ ❌ Schema validation failed:
273
+
274
+ • Post.user_id: Foreign key references non-existent table 'User'
275
+ ```
276
+
277
+ ### Custom Data Generators
278
+
279
+ Leverage any [Faker.js](https://fakerjs.dev/) method for realistic data generation:
280
+
281
+ ```typescript
282
+ t.varchar(100).generate('company.name')
283
+ t.varchar(50).generate('location.city')
284
+ t.integer().generate('number.int', { min: 1000, max: 9999 })
285
+ ```
286
+
287
+ Or write custom functions:
288
+
289
+ ```typescript
290
+ t.varchar(20).generate(() => {
291
+ const colors = ['red', 'blue', 'green', 'yellow']
292
+ return colors[Math.floor(Math.random() * colors.length)]
293
+ })
294
+
295
+ t.jsonb().generate((faker) => ({
296
+ preferences: {
297
+ theme: faker.helpers.arrayElement(['light', 'dark']),
298
+ language: faker.helpers.arrayElement(['en', 'es', 'fr'])
299
+ },
300
+ lastLogin: faker.date.recent().toISOString()
301
+ }))
302
+ ```
303
+
304
+ ## Command Line Interface
305
+
306
+ ```bash
307
+ bunx @doviui/dev-db generate <schemas> [options]
308
+
309
+ Arguments:
310
+ schemas Path to schema file or directory
311
+
312
+ Options:
313
+ -o, --output <dir> Output directory (default: "./mock-data")
314
+ -s, --seed <number> Random seed for reproducibility
315
+ -h, --help Display help
316
+ -v, --version Display version
317
+ ```
318
+
319
+ ### Programmatic API
320
+
321
+ For more control, create a custom generation script:
322
+
323
+ ```typescript
324
+ // scripts/generate-data.ts
325
+ import { MockDataGenerator, SchemaValidator } from '@doviui/dev-db'
326
+ import { schema } from './schemas/index'
327
+
328
+ // Validate schema
329
+ const validator = new SchemaValidator()
330
+ const errors = validator.validate(schema)
331
+
332
+ if (errors.length > 0) {
333
+ console.error('❌ Schema validation failed:')
334
+ errors.forEach(err => console.error(` • ${err.message}`))
335
+ process.exit(1)
336
+ }
337
+
338
+ // Generate data
339
+ const generator = new MockDataGenerator(schema, {
340
+ outputDir: './mock-data',
341
+ seed: process.env.SEED ? parseInt(process.env.SEED) : undefined
342
+ })
343
+
344
+ await generator.generate()
345
+ console.log('✓ Mock data generated successfully!')
346
+ ```
347
+
348
+ Add to package.json:
349
+
350
+ ```json
351
+ {
352
+ "scripts": {
353
+ "generate:data": "bun run scripts/generate-data.ts"
354
+ }
355
+ }
356
+ ```
357
+
358
+ Then run with:
359
+
360
+ ```bash
361
+ bun run generate:data
362
+ # or with a custom seed
363
+ SEED=42 bun run generate:data
364
+ ```
365
+
366
+ ## Real-World Examples
367
+
368
+ ### E-Commerce Platform
369
+
370
+ ```typescript
371
+ // schemas/ecommerce.schema.ts
372
+ import { t } from '@doviui/dev-db'
373
+
374
+ export default {
375
+ Customer: {
376
+ $count: 200,
377
+ id: t.uuid().primaryKey(),
378
+ email: t.varchar(255).unique().generate('internet.email'),
379
+ first_name: t.varchar(50).generate('person.firstName'),
380
+ last_name: t.varchar(50).generate('person.lastName'),
381
+ phone: t.varchar(20).generate('phone.number'),
382
+ created_at: t.timestamptz().default('now')
383
+ },
384
+
385
+ Product: {
386
+ $count: 100,
387
+ id: t.bigserial().primaryKey(),
388
+ name: t.varchar(200).generate('commerce.productName'),
389
+ description: t.text().generate('commerce.productDescription'),
390
+ price: t.decimal(10, 2).min(5).max(5000),
391
+ stock: t.integer().min(0).max(1000),
392
+ category: t.varchar(50).enum(['electronics', 'clothing', 'home', 'books'])
393
+ },
394
+
395
+ Order: {
396
+ $count: 500,
397
+ id: t.bigserial().primaryKey(),
398
+ customer_id: t.foreignKey('Customer', 'id').notNull(),
399
+ status: t.varchar(20).enum(['pending', 'processing', 'shipped', 'delivered']),
400
+ total: t.decimal(10, 2).min(10).max(10000),
401
+ created_at: t.timestamptz().default('now')
402
+ },
403
+
404
+ OrderItem: {
405
+ $count: 1500,
406
+ id: t.bigserial().primaryKey(),
407
+ order_id: t.foreignKey('Order', 'id').notNull(),
408
+ product_id: t.foreignKey('Product', 'id').notNull(),
409
+ quantity: t.integer().min(1).max(10),
410
+ price: t.decimal(10, 2)
411
+ }
412
+ }
413
+ ```
414
+
415
+ ### Blog Platform
416
+
417
+ ```typescript
418
+ // schemas/blog.schema.ts
419
+ import { t } from '@doviui/dev-db'
420
+
421
+ export default {
422
+ Author: {
423
+ $count: 50,
424
+ id: t.uuid().primaryKey(),
425
+ username: t.varchar(50).unique().generate('internet.userName'),
426
+ email: t.varchar(255).unique().generate('internet.email'),
427
+ bio: t.text().generate('lorem.paragraph'),
428
+ avatar_url: t.varchar(500).generate('image.avatar')
429
+ },
430
+
431
+ Article: {
432
+ $count: 300,
433
+ id: t.bigserial().primaryKey(),
434
+ author_id: t.foreignKey('Author', 'id'),
435
+ title: t.varchar(200).generate('lorem.sentence'),
436
+ slug: t.varchar(200).unique().generate('lorem.slug'),
437
+ content: t.text().generate('lorem.paragraphs', 5),
438
+ excerpt: t.varchar(500).generate('lorem.paragraph'),
439
+ published: t.boolean(),
440
+ published_at: t.timestamptz().nullable(),
441
+ created_at: t.timestamptz().default('now')
442
+ },
443
+
444
+ Tag: {
445
+ $count: 30,
446
+ id: t.serial().primaryKey(),
447
+ name: t.varchar(50).unique().generate('lorem.word')
448
+ },
449
+
450
+ ArticleTag: {
451
+ $count: 800,
452
+ article_id: t.foreignKey('Article', 'id'),
453
+ tag_id: t.foreignKey('Tag', 'id')
454
+ }
455
+ }
456
+ ```
457
+
458
+ ## Best Practices
459
+
460
+ ### Schema Design
461
+
462
+ **Define independent tables first** - Structure your schemas so tables without foreign keys are defined before those with dependencies. This simplifies validation and generation.
463
+
464
+ **Use realistic record counts** - Set `$count` values that reflect production ratios. For example, if users typically have 5 posts, generate 100 users and 500 posts.
465
+
466
+ **Leverage domain-specific generators** - Use Faker.js methods that match your domain (e.g., `company.name` for business data, `person.firstName` for user data) to generate realistic datasets.
467
+
468
+ ### Development Workflow
469
+
470
+ **Validate frequently** - Run generation regularly during schema development to catch errors early. The validator provides immediate feedback on structural issues.
471
+
472
+ **Use seeds for reproducibility** - In test environments and CI/CD, use the `--seed` option to generate identical datasets across runs. This ensures consistent test results.
473
+
474
+ **Organize by domain** - Group related tables in single schema files (e.g., `auth.schema.ts`, `orders.schema.ts`) for better maintainability and clearer relationships.
475
+
476
+ ## Troubleshooting
477
+
478
+ ### Foreign Key Validation Errors
479
+
480
+ **Problem**: `Foreign key references non-existent table 'TableName'`
481
+
482
+ **Solution**: Ensure all referenced tables are defined in your schema before tables that reference them:
483
+
484
+ ```typescript
485
+ // ✅ Correct - User defined before Post
486
+ export default {
487
+ User: {
488
+ id: t.bigserial().primaryKey(),
489
+ // ... other fields
490
+ },
491
+ Post: {
492
+ id: t.bigserial().primaryKey(),
493
+ user_id: t.foreignKey('User', 'id') // User exists in schema
494
+ }
495
+ }
496
+ ```
497
+
498
+ ### Unique Constraint Errors
499
+
500
+ **Problem**: `Could not generate unique value after 1000 attempts`
501
+
502
+ **Solution**: This occurs when unique constraints are too restrictive for the number of records. Consider these options:
503
+
504
+ - **Increase variety**: Use a more diverse Faker.js generator that produces more unique values
505
+ - **Reduce record count**: Lower the `$count` if you don't need that many records
506
+ - **Remove constraint**: If uniqueness isn't critical for your use case, remove the `.unique()` modifier
507
+
508
+ ### Circular Dependency Errors
509
+
510
+ **Problem**: `Circular dependency detected involving table: TableName`
511
+
512
+ **Solution**: dev-db cannot resolve circular foreign key relationships. Restructure your schema using one of these approaches:
513
+
514
+ - **Make relationships optional**: Use `.nullable()` on one of the foreign keys
515
+ - **Introduce a junction table**: Break the circular dependency with an intermediary table
516
+ - **Reconsider the model**: Circular dependencies often indicate a modeling issue
517
+
518
+ ## Contributing
519
+
520
+ We welcome contributions! Whether you're fixing bugs, improving documentation, or proposing new features, your input helps make dev-db better for everyone.
521
+
522
+ Please read our [Contributing Guide](CONTRIBUTING.md) to get started.
523
+
524
+ ## License
525
+
526
+ MIT License - see [LICENSE](LICENSE) for details
527
+
528
+ ## Acknowledgments
529
+
530
+ dev-db is built with:
531
+ - [Faker.js](https://fakerjs.dev/) - High-quality fake data generation
532
+ - [Bun](https://bun.sh/) - Fast JavaScript runtime and toolkit
package/index.ts ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @doviui/dev-db - Generate realistic mock JSON databases from TypeScript schemas
3
+ *
4
+ * @packageDocumentation
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { t, MockDataGenerator, SchemaValidator } from '@doviui/dev-db';
9
+ *
10
+ * // Define schema
11
+ * const schema = {
12
+ * User: {
13
+ * $count: 100,
14
+ * id: t.bigserial().primaryKey(),
15
+ * email: t.varchar(255).unique().notNull().generate('internet.email'),
16
+ * age: t.integer().min(18).max(100)
17
+ * }
18
+ * };
19
+ *
20
+ * // Validate schema
21
+ * const validator = new SchemaValidator();
22
+ * const errors = validator.validate(schema);
23
+ *
24
+ * // Generate data
25
+ * const generator = new MockDataGenerator(schema, {
26
+ * outputDir: './mock-data',
27
+ * seed: 42
28
+ * });
29
+ * await generator.generate();
30
+ * ```
31
+ */
32
+
33
+ // Re-export public API
34
+ export { t } from './src/schema-builder';
35
+ export { MockDataGenerator } from './src/generator';
36
+ export { SchemaValidator } from './src/validator';
37
+ export type { Schema, TableConfig, FieldConfig, Generator } from './src/types';
38
+ export type { ValidationError } from './src/validator';
39
+ export type { GeneratorOptions } from './src/generator';
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@doviui/dev-db",
3
+ "version": "0.1.0",
4
+ "description": "TypeScript-first mock database generator for rapid application development",
5
+ "main": "index.ts",
6
+ "module": "index.ts",
7
+ "types": "index.ts",
8
+ "type": "module",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./index.ts",
12
+ "types": "./index.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "index.ts",
17
+ "src/**/*.ts",
18
+ "README.md",
19
+ "LICENSE"
20
+ ],
21
+ "keywords": [
22
+ "mock",
23
+ "database",
24
+ "generator",
25
+ "faker",
26
+ "typescript",
27
+ "testing",
28
+ "development"
29
+ ],
30
+ "license": "MIT",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/calvin-kimani/dev-db.git"
34
+ },
35
+ "bugs": {
36
+ "url": "https://github.com/calvin-kimani/dev-db/issues"
37
+ },
38
+ "homepage": "https://github.com/calvin-kimani/dev-db#readme",
39
+ "author": "Calvin Kimani",
40
+ "devDependencies": {
41
+ "@types/bun": "latest"
42
+ },
43
+ "peerDependencies": {
44
+ "typescript": "^5"
45
+ },
46
+ "dependencies": {
47
+ "@faker-js/faker": "^10.1.0"
48
+ }
49
+ }