@indexeddb-orm/idb-orm
v0.0.3
Published
TypeScript ORM wrapper for indexeddb with Zod runtime validation, build on top of dexie.js
Downloads
9,551
Maintainers
Readme
Dexie ORM
TypeScript ORM wrapper for indexed-db with Zod runtime validation, built on the top of dexie.js.
View Homepage - Interactive documentation and examples
Features
TypeScript Support - Full type safety with generics
Zod Validation - Runtime validation with Zod schemas
Config-based entities - Define entities with a simple
defineEntity(...)APIDexie Compatibility - All Dexie.js operations supported
Clean API - Simple and intuitive API design
Installation
npm install @indexeddb-orm/idb-orm dexie zodImportant Notes
Dexie Dependencies
This library includes Dexie.js internally. To ensure that liveQuery works properly, you need to configure Vite to dedupe Dexie.
// In your vite.config.ts, add:
import { defineConfig } from 'vite';
export default defineConfig({
resolve: {
dedupe: ['dexie'],
},
// ... other config
});
// This ensures liveQuery works correctly
// Without dedupe, liveQuery may not function properlyBuilt on Dexie.js
This library is built on top of Dexie.js - a powerful wrapper for IndexedDB. All Dexie.js methods and features are available through the db object.
// All Dexie.js methods work with our library
const db = await Database.createDatabase({...});
// Direct Dexie.js operations
await db.transaction('rw', db.users, async () => {
await db.users.add({ name: 'John', email: '[email protected]' });
});
// Dexie.js query methods
const users = await db.users
.where('age')
.above(18)
.and(user => user.name.startsWith('J'))
.toArray();
// Dexie.js liveQuery (reactive queries)
import { liveQuery } from 'dexie';
const observableUsers = liveQuery(() =>
db.users.where('active').equals(true).toArray()
);Benefits: You get all the power of Dexie.js plus our ORM features like entity validation, relations, and cloud sync.
Index Requirements for Queries
Critical: When searching by any field, you MUST create an index on that field. Queries without proper indexes will fail.
const UserSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string(),
age: z.number()
});
defineEntity(User, {
schema: UserSchema,
indexes: [
{ key: 'email' }, // Required for email queries
{ key: 'age' }, // Required for age queries
{ key: 'name' } // Required for name queries
]
});Compound Indexes for Complex Queries
For queries involving multiple fields, you need compound indexes. Single field indexes won't work for multi-field queries.
defineEntity(Post, {
schema: PostSchema,
compoundIndexes: [
{ key: ['category', 'status'] },
{ key: ['authorId', 'createdAt'] }
]
});Usage
1. Define Entities
import { BaseEntity, defineEntity } from '@indexeddb-orm/idb-orm';
import { z } from 'zod';
// Zod schema for validation
const UserSchema = z.object({
id: z.number().optional(),
name: z.string().min(2, 'Name must be at least 2 characters'),
email: z.string().email('Invalid email format'),
age: z.number().min(18, 'Must be at least 18 years old'),
createdAt: z.number(),
updatedAt: z.number(),
isActive: z.boolean().default(true),
tags: z.array(z.string()).default([]),
metadata: z.record(z.string(), z.unknown()).default({}),
});
export class UserEntity extends BaseEntity<number> {
name!: string;
email!: string;
age!: number;
createdAt!: number;
updatedAt!: number;
isActive!: boolean;
tags!: string[];
metadata!: Record<string, unknown>;
}
defineEntity(UserEntity, {
tableName: 'users',
schema: UserSchema,
columns: {
name: { required: true, indexed: true },
email: { required: true, unique: true },
age: { indexed: true },
createdAt: { indexed: true },
updatedAt: { indexed: true },
isActive: { indexed: true },
tags: {},
metadata: {},
},
// Example relations (optional)
// relations: {
// posts: { type: 'one-to-many', target: PostEntity, foreignKey: 'authorId' },
// },
});2. Create Database
import { Database } from '@indexeddb-orm/idb-orm';
import { UserEntity } from './entities/User';
import { PostEntity } from './entities/Post';
export const db = Database.createDatabase({
name: 'MyApp',
version: 1,
entities: [UserEntity, PostEntity],
config: {
onSchemaChangeStrategy: 'all',
cloudSync: {
databaseUrl: 'https://your-sync-server.com',
enableOfflineQueue: true,
syncInterval: 30000
}
},
});Database Configuration Options
The createDatabase() method accepts the following configuration options:
Basic Configuration
const db = Database.createDatabase({
name: string, // Required: Database name
version: number, // Required: Schema version
entities: EntityConstructor[], // Required: Array of entity classes
config?: { // Optional: Additional configuration
// Schema change handling
onSchemaChangeStrategy?: 'selective' | 'all',
// Migrations list
migrations?: Migration[],
// Cloud synchronization
cloudSync?: CloudSyncConfig
}
});Schema Change Strategy Options
onSchemaChangeStrategy - Defines how to handle database schema changes:
'selective'(recommended for production): Only resets tables that have schema changes, preserving data in unchanged tables'all': Resets the entire database when any schema change is detected, useful for development
Cloud Sync Configuration Options
CloudSyncConfig - Configuration for cloud synchronization:
interface CloudSyncConfig {
databaseUrl: string; // Required: Base URL of the sync server
enableOfflineSupport?: boolean; // Optional: Queue changes when offline (default: false)
syncInterval?: number; // Optional: Auto-sync interval in milliseconds (default: 30000)
// Note: Authentication is handled by Dexie Cloud addon configuration
}Cloud Sync Options:
databaseUrl(required): The base URL of your synchronization serverenableOfflineSupport(optional): Iftrue, changes are queued when offline and synced when connection is restoredsyncInterval(optional): Automatic synchronization interval in milliseconds (default: 30 seconds)
Authentication Note: Authentication for cloud sync is handled by the Dexie Cloud addon configuration, not through this interface. You need to configure authentication separately when setting up the Dexie Cloud addon.
Schema Change Strategy Examples
// Option 1: Reset only changed tables (recommended for production)
const db = Database.createDatabase({
name: 'MyApp',
version: 1,
entities: [UserEntity, PostEntity],
config: {
onSchemaChangeStrategy: 'selective' // Only reset tables that changed
}
});
// Option 2: Reset entire database on schema changes
const db = Database.createDatabase({
name: 'MyApp',
version: 1,
entities: [UserEntity, PostEntity],
config: {
onSchemaChangeStrategy: 'all' // Reset all data when schema changes
}
});Migration Configuration
const db = Database.createDatabase({
name: 'MyApp',
version: 2,
entities: [UserEntity, PostEntity],
config: {
migrations: [
{
version: 2,
name: 'Add fullName field',
up: async (db) => {
await db.getRepository(UserEntity).toCollection().modify(user => {
user.fullName = `${user.firstName} ${user.lastName}`;
});
},
down: async (db) => {
await db.getRepository(UserEntity).toCollection().modify(user => {
delete user.fullName;
});
}
}
]
}
});Cloud Synchronization Configuration
const db = Database.createDatabase({
name: 'MyApp',
version: 1,
entities: [UserEntity, PostEntity],
config: {
cloudSync: {
databaseUrl: 'https://your-sync-server.com', // Required: Sync server URL
enableOfflineSupport: true, // Optional: Queue changes when offline
syncInterval: 30000 // Optional: Auto-sync interval (30s)
}
}
});Complete Configuration Example
const db = Database.createDatabase({
name: 'MyApp',
version: 3,
entities: [UserEntity, PostEntity, CommentEntity],
config: {
// Handle schema changes by resetting only affected tables
onSchemaChangeStrategy: 'selective',
// Define migrations for version upgrades
migrations: [
{
version: 2,
name: 'Add user profiles',
up: async (db) => {
// Migration logic for version 2
}
},
{
version: 3,
name: 'Add comment system',
up: async (db) => {
// Migration logic for version 3
}
}
],
// Enable cloud synchronization
cloudSync: {
databaseUrl: 'https://api.myapp.com/sync',
enableOfflineSupport: true,
syncInterval: 60000 // Sync every minute
}
}
});3. Basic CRUD Operations
// Prefer explicit repositories for strict typing
const users = await db.getRepository(UserEntity).toArray(); // Type: UserEntity[]
const posts = await db.getRepository(PostEntity).toArray(); // Type: PostEntity[]
// Create new entity with validation in one call
import { newEntity } from '@indexeddb-orm/idb-orm';
const newUser = newEntity(UserEntity, {
name: 'John Doe',
email: '[email protected]',
age: 25,
createdAt: Date.now(),
updatedAt: Date.now(),
tags: ['developer'],
metadata: { source: 'manual' },
});
// Save to database
await db.getRepository(UserEntity).add(newUser);
// Query with full Dexie.js API
const activeUsers = await db.getRepository(UserEntity)
.where('isActive')
.equals(true)
.toArray();4. Entity Relations
// Define entities with relations
defineEntity(UserEntity, {
tableName: 'users',
schema: UserSchema,
columns: { /* ... */ },
relations: {
posts: {
type: 'one-to-many',
target: PostEntity,
foreignKey: 'authorId'
},
profile: {
type: 'one-to-one',
target: ProfileEntity,
foreignKey: 'userId'
}
}
});
defineEntity(PostEntity, {
tableName: 'posts',
schema: PostSchema,
columns: { /* ... */ },
relations: {
author: {
type: 'many-to-one',
target: UserEntity,
foreignKey: 'authorId'
},
tags: {
type: 'many-to-many',
target: TagEntity,
joinTable: 'post_tags'
}
}
});
// Load relations
const userWithPosts = await db.loadRelations({
entity: user,
entityClass: UserEntity,
relationNames: ['posts', 'profile']
});
// Load specific relation
const userPosts = await db.loadRelationByName({
entity: user,
entityClass: UserEntity,
relationName: 'posts'
});
// Save entity with all its relations
const savedUser = await db.saveWithRelations({
entity: user,
entityClass: UserEntity
});
// Delete entity with cascade handling for relations
await db.deleteWithRelations({
entity: user,
entityClass: UserEntity
});5. Reactive Queries with liveQuery
Use Dexie's liveQuery for reactive data that automatically updates when the database changes. Works with all major frameworks:
React Example
import { liveQuery } from 'dexie';
import { useObservable } from 'dexie-react-hooks';
import { Database } from 'indexed-db-orm';
import { User } from './entities/User';
function UserList() {
const users = useObservable(
liveQuery(() => {
const userRepo = db.getRepository(User);
return userRepo.where('active').equals(true).toArray();
})
);
return (
<div>
{users?.map(user => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
}Vue Example
import { liveQuery } from 'dexie';
import { ref, onMounted, onUnmounted } from 'vue';
import { Database } from 'indexed-db-orm';
import { User } from './entities/User';
export default {
setup() {
const users = ref<User[]>([]);
let subscription;
onMounted(() => {
subscription = liveQuery(() => {
const userRepo = db.getRepository(User);
return userRepo.where('active').equals(true).toArray();
}).subscribe(result => {
users.value = result;
});
});
onUnmounted(() => {
subscription?.unsubscribe();
});
return { users };
}
};Svelte Example
import { liveQuery } from 'dexie';
import { onMount, onDestroy } from 'svelte';
import { Database } from 'indexed-db-orm';
import { User } from './entities/User';
let users: User[] = [];
let subscription;
onMount(() => {
subscription = liveQuery(() => {
const userRepo = db.getRepository(User);
return userRepo.where('active').equals(true).toArray();
}).subscribe(result => {
users = result;
});
});
onDestroy(() => {
subscription?.unsubscribe();
});Angular Example
import { liveQuery } from 'dexie';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
import { Database } from 'indexed-db-orm';
import { User } from './entities/User';
@Component({
selector: 'app-user-list',
template: '<div *ngFor="let user of users">{{user.name}}</div>'
})
export class UserListComponent implements OnInit, OnDestroy {
users: User[] = [];
private subscription?: Subscription;
ngOnInit() {
this.subscription = liveQuery(() => {
const userRepo = db.getRepository(User);
return userRepo.where('active').equals(true).toArray();
}).subscribe(result => {
this.users = result;
});
}
ngOnDestroy() {
this.subscription?.unsubscribe();
}
}6. Advanced Queries and Aggregation
// Aggregation operations
const result = await db.aggregate({
entityClass: PostEntity,
options: {
where: { category: 'tech' },
sort: { field: 'views', direction: 'desc' },
limit: 10,
count: true,
sum: ['views'],
avg: ['likes'],
groupBy: ['category']
}
});
// Complex filtering and sorting
const topPosts = await db.getRepository(PostEntity)
.where('published')
.equals(true)
.and(post => post.views > 100)
.orderBy('views')
.reverse()
.limit(5)
.toArray();6. Entity Validation
// Manual validation
const user = new UserEntity();
user.name = 'A'; // Too short
user.email = 'invalid-email'; // Invalid format
const result = user.validate();
if (!result.isValid) {
console.log(result.errors);
// ['name: Name must be at least 2 characters', 'email: Invalid email format']
}
// Validation with error throwing
try {
user.validateOrThrow();
} catch (error) {
console.log('Validation failed:', error.message);
}
// Initialize with validation
const validUser = new UserEntity().init({
name: 'John Doe',
email: '[email protected]',
age: 25
});7. Database Management
// Check for schema changes
const hasChanges = await db.checkSchemaChanges();
if (hasChanges) {
await db.performSelectiveReset(); // Reset only changed tables
// or
await db.resetDatabase(); // Reset entire database
}
// Clear all data
await db.clearAllData();
// Run migrations
await db.runMigrations([
{
version: 2,
up: async (db) => {
await db.getRepository(UserEntity).toCollection().modify(user => {
user.fullName = `${user.firstName} ${user.lastName}`;
});
}
}
]);8. Cloud Synchronization
Installation
npm install dexie-cloud-addonConfiguration
// Basic cloud sync configuration
const db = Database.createDatabase({
name: 'MyApp',
version: 1,
entities: [UserEntity, PostEntity],
config: {
cloudSync: {
databaseUrl: 'https://your-database-url.dexie.cloud',
enableOfflineSupport: true,
syncInterval: 30000 // 30 seconds
}
}
});
// Enable cloud sync manually
await db.enableCloudSync({
databaseUrl: 'https://your-sync-server.com',
enableOfflineSupport: true,
syncInterval: 30000
});Cloud Sync API
// Check sync status
const status = db.getSyncStatus();
console.log('Sync enabled:', status.enabled);
console.log('Last sync:', status.lastSync);
console.log('Online:', status.isOnline);
// Manual sync
await db.sync();
// Sync specific tables
await db.syncTables(['users', 'posts']);
// Check if cloud sync is enabled
const isEnabled = db.isCloudSyncEnabled();
// Get cloud sync configuration
const config = db.getCloudSyncConfig();
// Disable cloud sync
db.disableCloudSync();Automatic Synchronization
// Configure automatic sync with interval
const db = Database.createDatabase({
name: 'MyApp',
version: 1,
entities: [UserEntity, PostEntity],
config: {
cloudSync: {
databaseUrl: 'https://your-database-url.dexie.cloud',
syncInterval: 60000 // Sync every minute
}
}
});React Integration Example
import { useState, useEffect } from 'react';
import { useLiveQuery } from 'dexie-react-hooks';
function MyComponent() {
const [syncStatus, setSyncStatus] = useState({ enabled: false });
// Data with automatic synchronization
const users = useLiveQuery(() => db.getRepository(UserEntity).toArray());
useEffect(() => {
const status = db.getSyncStatus();
setSyncStatus(status);
}, []);
const handleSync = async () => {
try {
await db.sync();
alert('Synchronization completed!');
} catch (error) {
alert(`Sync error: ${error.message}`);
}
};
return (
<div>
<h2>Status: {syncStatus.enabled ? 'Enabled' : 'Disabled'}</h2>
<button onClick={handleSync}>Sync Now</button>
{users?.map(user => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
}Troubleshooting
// Check if cloud sync is configured
const config = db.getCloudSyncConfig();
if (!config) {
await db.enableCloudSync({
databaseUrl: 'https://your-database-url.dexie.cloud'
});
}
// Check sync status for debugging
const status = db.getSyncStatus();
console.log('Online:', status.isOnline);
console.log('Last sync:', status.lastSync);
// Try manual sync if automatic sync fails
await db.sync();
9. Compound Indexes
Compound indexes allow you to create indexes on multiple columns for better query performance.
Defining Compound Indexes
import { BaseEntity, defineEntity } from '@indexeddb-orm/idb-orm';
import { z } from 'zod';
// Zod schema for validation
const UserSchema = z.object({
id: z.number().optional(),
name: z.string(),
email: z.string().email(),
age: z.number(),
isActive: z.boolean(),
});
export class UserEntity extends BaseEntity {
name!: string;
email!: string;
age!: number;
isActive!: boolean;
}
// Define entity with compound indexes
defineEntity(UserEntity, {
tableName: 'users',
schema: UserSchema,
columns: {
name: { indexed: true },
email: { indexed: true, unique: true },
age: { indexed: true },
isActive: { indexed: true },
},
compoundIndexes: [
{
columns: ['name', 'email'],
unique: false,
name: 'name_email_index'
},
{
columns: ['age', 'isActive'],
unique: false,
name: 'age_active_index'
},
{
columns: ['email'],
unique: true,
name: 'unique_email_index'
}
]
});Querying with Compound Indexes
// Query using compound index (name + email)
const users = await db.getRepository(UserEntity)
.where(['name', 'email'])
.equals(['John Doe', '[email protected]'])
.toArray();
// Query using compound index (age + isActive)
const activeAdults = await db.getRepository(UserEntity)
.where(['age', 'isActive'])
.above([18, 1]) // age > 18, isActive = true
.toArray();
// Query using unique compound index
const user = await db.getRepository(UserEntity)
.where('email')
.equals('[email protected]')
.first();Different Query Operators
// equals - exact match
const users = await db.getRepository(UserEntity)
.where(['name', 'email'])
.equals(['John', '[email protected]'])
.toArray();
// above - greater than
const adults = await db.getRepository(UserEntity)
.where(['age', 'isActive'])
.above([18, 1])
.toArray();
// below - less than
const youngUsers = await db.getRepository(UserEntity)
.where(['age'])
.below([25])
.toArray();
// between - between values
const middleAged = await db.getRepository(UserEntity)
.where(['age'])
.between([25, 50])
.toArray();Real-world Examples
// 1. User search by name and email
defineEntity(UserEntity, {
tableName: 'users',
schema: UserSchema,
columns: {
name: { indexed: true },
email: { indexed: true },
},
compoundIndexes: [
{ columns: ['name', 'email'], name: 'name_email_index' }
]
});
// Usage: Find user by exact name and email
const user = await db.getRepository(UserEntity)
.where(['name', 'email'])
.equals(['John Doe', '[email protected]'])
.first();
// 2. Active adults filter
defineEntity(UserEntity, {
tableName: 'users',
schema: UserSchema,
columns: {
age: { indexed: true },
isActive: { indexed: true },
},
compoundIndexes: [
{ columns: ['age', 'isActive'], name: 'age_active_index' }
]
});
// Usage: Find active adults
const activeAdults = await db.getRepository(UserEntity)
.where(['age', 'isActive'])
.above([18, 1])
.toArray();
// 3. Posts by date and category
defineEntity(PostEntity, {
tableName: 'posts',
schema: PostSchema,
columns: {
createdAt: { indexed: true },
category: { indexed: true },
},
compoundIndexes: [
{ columns: ['createdAt', 'category'], name: 'date_category_index' }
]
});
// Usage: Find recent posts in specific category
const recentTechPosts = await db.getRepository(PostEntity)
.where(['createdAt', 'category'])
.above([Date.now() - 7 * 24 * 60 * 60 * 1000, 'tech'])
.toArray();Compound Index Benefits
- Query Performance: Faster searches on multiple columns
- Uniqueness: Guarantee unique combinations of values
- Flexibility: Create indexes on any column combinations
- Optimization: Better performance for complex queries
Vite note: ensure a single Dexie instance for live queries
If useLiveQuery doesn't re-render with this library's Database, make sure Vite bundles a single Dexie copy by deduping Dexie:
// vite.config.ts
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [react()],
resolve: { dedupe: ['dexie'] },
});This ensures the app and the library share the same Dexie singleton so reactivity works correctly.
Indexing Note
When querying with where('field') or sorting with orderBy('field'), ensure the field is indexed in your entity definition:
defineEntity(PostEntity, {
tableName: 'posts',
columns: {
createdAt: { indexed: true },
published: { indexed: true },
likes: { indexed: true },
},
});If you change indexes, bump your database version or run a migration so Dexie can apply the schema update.
Example Applications
The library includes comprehensive demo applications showcasing all features across different frameworks:
Available Demo Apps
React Demo App
- Framework: React 19 + TypeScript
- UI Library: Material-UI (MUI)
- Features: Live queries, TypeScript demo, Cloud sync, Aggregations
- Run:
cd react-demo-app && npm install && npm run dev - URL:
http://localhost:5173
Vue Demo App
- Framework: Vue 3 + TypeScript
- UI Library: Vuetify 3
- Features: Reactive components, Cloud sync, Entity management
- Run:
cd vue-demo-app && npm install && npm run dev - URL:
http://localhost:5173
Svelte Demo App
- Framework: SvelteKit + TypeScript
- UI Library: Material-UI (MUI)
- Features: Server-side rendering, Live queries, TypeScript integration
- Run:
cd svelte-demo-app && npm install && npm run dev - URL:
http://localhost:5173
Angular Demo App
- Framework: Angular 17 + TypeScript
- UI Library: Angular Material
- Features: Services, Dependency injection, Reactive forms
- Run:
cd angular-demo-app && npm install && npm start - URL:
http://localhost:4200
Demo App Features
All demo applications showcase:
Core Features
- Entity Definition - Using
defineEntity()API - Zod Validation - Runtime validation with error handling
- Relations - One-to-one, one-to-many, many-to-many relationships
- Aggregations - Count, sum, average, min, max operations
- Live Queries - Reactive data with
useLiveQuery() - TypeScript - Full type safety and IntelliSense
Advanced Features
- Cloud Sync - Dexie Cloud synchronization
- Migrations - Database schema migrations
- Compound Indexes - Multi-column indexing
- Entity Management - CRUD operations with relations
- Error Handling - Validation errors and user feedback
Demo App Structure
Each demo app follows similar structure:
demo-app/
├── src/
│ ├── entities/ # Entity definitions
│ ├── database/ # Database configuration
│ └── migrations/ # Database migrations
├── package.json
└── README.mdEach demo is fully functional and can serve as a starting point for your own applications!
API Reference
Core Classes
Database
Main database class extending Dexie with ORM capabilities.
Static Methods:
Database.createDatabase(params)- Create database with entity registration
Instance Methods:
getRepository<T>(entityClass)- Get typed repository for entityaggregate<T>(params)- Perform aggregation operationsclearAllData()- Clear all data from databaseresetDatabase()- Reset database when schema changescheckSchemaChanges()- Check if schema has changedperformSelectiveReset()- Reset only changed tablesrunMigrations(migrations)- Run database migrationsgetTypedTable<T>(entityClass)- Get typed table for entitygetTableForEntity<T>(entityClass)- Get table with proper typinggetEntities()- Get all registered entitiesgetEntity(tableName)- Get entity by table nameloadRelations<T>(params)- Load relations for entityloadRelationByName<T, K>(params)- Load specific relationsaveWithRelations<T>(params)- Save entity with relationsdeleteWithRelations<T>(params)- Delete entity with cascadesync()- Manual cloud syncgetSyncStatus()- Get cloud sync statusenableCloudSync(config)- Enable cloud synchronizationdisableCloudSync()- Disable cloud syncisCloudSyncEnabled()- Check if cloud sync is enabledgetCloudSyncConfig()- Get cloud sync configurationsyncTables(tableNames)- Sync specific tables
BaseEntity<TKey>
Base class for all entities with validation capabilities.
Methods:
validate(): ValidationResult- Validate entity against schemavalidateOrThrow(): void- Validate and throw error if invalidinit(data): this- Initialize entity with data and validate
EntitySchema<T>
Schema management for entities.
Methods:
getTableName(): string- Get table name for entitygetSchema(): ZodSchema | undefined- Get Zod schemagetColumns(): Record<string, ColumnOptions>- Get column metadatavalidate(data): ValidationResult- Validate data against schemacreate(data?): T- Create new entity instance
Entity Definition
defineEntity(EntityClass, options)
Define entity with metadata and configuration.
Parameters:
EntityClass- Entity constructor classoptions- Entity configuration object
Options:
interface EntityOptions {
tableName?: string; // Custom table name
schema?: ZodSchema; // Zod validation schema
timestamps?: boolean; // Enable timestamps
columns?: Record<string, ColumnOptions>;
relations?: Record<string, RelationOptions>;
compoundIndexes?: CompoundIndexOptions[];
}newEntity(EntityClass, data)
Create new entity instance with validation.
Parameters:
EntityClass- Entity constructordata- Partial entity data
Returns: Fully initialized and validated entity instance
Decorators
@Entity(options?)
Class decorator for entity definition.
@Column(options?)
Property decorator for column configuration.
@Relation(options)
Property decorator for relation definition.
Relation Types:
@OneToOne(target, options?)- One-to-one relation@OneToMany(target, foreignKey)- One-to-many relation@ManyToMany(target, joinTable)- Many-to-many relation
Type Definitions
EntityConstructor<T>
interface EntityConstructor<T extends BaseEntity = BaseEntity> {
new (): T;
schema?: ZodSchema;
tableName?: string;
}ColumnOptions
interface ColumnOptions {
kind?: 'string' | 'number' | 'boolean' | 'array' | 'object';
unique?: boolean;
indexed?: boolean;
required?: boolean;
default?: unknown;
primaryKey?: boolean;
autoIncrement?: boolean;
}RelationOptions
interface RelationOptions {
type: 'one-to-one' | 'one-to-many' | 'many-to-many';
target: EntityConstructor | string;
foreignKey?: string;
joinTable?: string;
cascade?: boolean;
eager?: boolean;
}ValidationResult
interface ValidationResult {
isValid: boolean;
errors: string[];
}DatabaseConfig
interface DatabaseConfig {
name: string;
version: number;
entities: EntityConstructor[];
onSchemaChangeStrategy?: 'selective' | 'all';
migrations?: Migration[];
cloudSync?: CloudSyncConfig;
}CloudSyncConfig
interface CloudSyncConfig {
databaseUrl: string;
enableOfflineSupport?: boolean;
syncInterval?: number;
}Migration
interface Migration {
version: number;
name: string;
up: (db: Dexie) => Promise<void>;
down?: (db: Dexie) => Promise<void>;
}AggregationOptions<T>
interface AggregationOptions<T extends BaseEntity> {
where?: Partial<T>;
count?: boolean;
sum?: (keyof T)[];
avg?: (keyof T)[];
min?: (keyof T)[];
max?: (keyof T)[];
groupBy?: keyof T;
include?: string[];
limit?: number;
sort?: {
field: keyof T;
direction: 'asc' | 'desc';
};
}AggregationResult
interface AggregationResult {
count?: number;
sum?: Record<string, number>;
avg?: Record<string, number>;
min?: Record<string, number>;
max?: Record<string, number>;
groups?: Array<{
key: unknown;
count: number;
sum?: Record<string, number>;
avg?: Record<string, number>;
min?: Record<string, number>;
max?: Record<string, number>;
}>;
data?: unknown[];
}Error Classes
ValidationError
Error thrown when entity validation fails.
Properties:
message: string- Error messageerrors: string[]- Array of validation errors
Utility Functions
newEntity(EntityClass, data)
Factory function for creating validated entities.
defineEntity(EntityClass, options)
Function for defining entity metadata.
Schema Change Strategies
'selective'
Only resets tables that have schema changes, preserving data in unchanged tables.
'all'
Resets the entire database when any schema change is detected.
Cloud Sync Status
interface SyncStatus {
enabled: boolean;
lastSync?: Date;
isOnline?: boolean;
}License
MIT
