Deprecated: Function get_magic_quotes_gpc() is deprecated in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 99

Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 619

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1169

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176
8000 GitHub - maifeeulasad/idb-ts: Use IndexedDB with TypeScript in a declarative style
Nothing Special   »   [go: up one dir, main page]

Skip to content

maifeeulasad/idb-ts

Repository files navigation

πŸš€ idb-ts

npm version minified minified + gzipped

GitHub stars GitHub watchers Commits after release

πŸ“Œ Introduction

idb-ts is a lightweight, declarative, and type-safe way to work with IndexedDB using TypeScript. Effortlessly perform CRUD operations on your database with clean, structured code! πŸ”₯

πŸ“¦ Installation

Install via npm and start using IndexedDB like a pro! ⚑

npm i idb-ts

✨ Features

  • βœ… Declarative & Type-Safe - Define your data models with decorators.
  • ⚑ Easy CRUD Operations - Perform create, read, update, and delete seamlessly.
  • πŸš€ Fully Typed API - Benefit from TypeScript’s powerful type system.
  • 🏎️ Performance Optimized - Minimal overhead with IndexedDB's native capabilities.
  • πŸ”„ Schema Versioning - Manage database schema evolution with automatic migration support.
  • πŸ”‘ Advanced Key Management - Auto-increment, UUID, timestamp, custom generators, and composite keys.

πŸ“– Example Usage

πŸ—οΈ Declaring Entities

Use decorators to define your data models. Each class must have exactly one @KeyPath() and be decorated with @DataClass().

import { Database, DataClass, KeyPath, Index } from "idb-ts";

@DataClass()
class User {
  @KeyPath()
  id!: string;

  @Index()
  email!: string;

  name!: string;
  age!: number;

  constructor(id: string, name: string, age: number, email?: string) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.email = email || `${name.toLowerCase()}@example.com`;
  }
}

@DataClass()
class Location {
  @KeyPath()
  id!: string;

  @Index()
  city!: string;

  country!: string;

  constructor(id: string, city: string, country: string) {
    this.id = id;
    this.city = city;
    this.country = country;
  }
}

πŸ”„ CRUD Operations

Perform database operations using the repository API:

const db = await Database.build("idb-crud", [User, Location]);

const alice = new User("u1", "Alice", 25);
const bob = new User("u2", "Bob", 30);
const nyc = new Location("1", "New York", "USA");
const sf = new Location("2", "San Francisco", "USA");

await db.User.create(alice);
await db.User.create(bob);
await db.Location.create(nyc);
await db.Location.create(sf);

const readAlice = await db.User.read("u1");
console.log("πŸ‘€ Read user:", readAlice);

alice.age = 26;
await db.User.update(alice);

const users = await db.User.list();
console.log("πŸ“‹ All users:", users);

// Pagination
const page1 = await db.User.listPaginated(1, 2); // page 1, 2 users per page
console.log("πŸ“„ Page 1:", page1);

await db.User.delete("u1");
console.log("❌ User Alice deleted.");

const remainingUsers = await db.User.list();
console.log("πŸ” Remaining users:", remainingUsers);

const locations = await db.Location.list();
console.log("🌍 All locations:", locations);

πŸ” Indexing Support

Create indexes on fields for fast querying. Query indexes using the repository API:

@DataClass()
class Product {
  @KeyPath()
  id!: string;

  @Index()
  category!: string;

  @Index()
  price!: number;

  name!: string;
  description!: string;

  constructor(id: string, category: string, price: number, name: string, description: string) {
    this.id = id;
    this.category = category;
    this.price = price;
    this.name = name;
    this.description = description;
  }
}

const db = await Database.build("products-db", [Product]);

const electronics = await db.Product.findByIndex('category', 'Electronics');
const expensiveItems = await db.Product.findByIndex('price', 999.99);
const firstElectronic = await db.Product.findOneByIndex('category', 'Electronics');

Index Methods:

  • findByIndex(indexName, value): Promise<T[]> - Find all records matching the index value
  • findOneByIndex(indexName, value): Promise<T | undefined> - Find the first record matching the index value

Error Handling

  • If you query a non-existent index, an error is thrown:
    await db.Product.findByIndex('nonexistent', 'value'); // throws

πŸ”‘ Multi-Field & Composite Key Support

idb-ts provides flexible key management options including auto-increment keys, key generators, and composite keys for complex data relationships.

Auto-Increment Keys

Perfect for entities where you want the database to automatically generate sequential IDs:

@DataClass()
class Task {
  @KeyPath({ autoIncrement: true })
  id!: number;

  title!: string;
  completed!: boolean;

  constructor(title: string, completed = false) {
    this.title = title;
    this.completed = completed;
  }
}

const db = await Database.build("tasks-db", [Task]);

// IDs are automatically generated: 1, 2, 3, etc.
const task1 = await db.Task.create(new Task("Learn TypeScript"));
const task2 = await db.Task.create(new Task("Build amazing apps"));
console.log(task1.id); // 1
console.log(task2.id); // 2

Key Generators

Generate keys automatically using built-in generators:

UUID Keys

@DataClass()
class Document {
  @KeyPath({ generator: 'uuid' })
  uuid!: string;

  @Index()
  category!: string;

  title!: string;
  content!: string;

  constructor(category: string, title: string, content: string) {
    this.category = category;
    this.title = title;
    this.content = content;
  }
}

const db = await Database.build("docs-db", [Document]);

const doc = await db.Document.create(new Document("tutorial", "Getting Started", "Welcome..."));
console.log(doc.uuid); // e.g., "a1b2c3d4-e5f6-7890-abcd-ef1234567890"

Timestamp Keys

@DataClass()
class Event {
  @KeyPath({ generator: 'timestamp' })
  timestamp!: number;

  @Index()
  type!: string;

  data!: any;

  constructor(type: string, data: any) {
    this.type = type;
    this.data = data;
  }
}

const event = await db.Event.create(new Event("user_login", { userId: "123" }));
console.log(event.timestamp); // e.g., 1696118400000

Random Keys

@DataClass()
class Session {
  @KeyPath({ generator: 'random' })
  sessionId!: string;

  userId!: string;
  expiresAt!: Date;

  constructor(userId: string, expiresAt: Date) {
    this.userId = userId;
    this.expiresAt = expiresAt;
  }
}

const session = await db.Session.create(new Session("user123", new Date()));
console.log(session.sessionId); // e.g., "xyz789abc123"

Custom Key Generators

Create your own key generation logic:

@DataClass()
class Invoice {
  @KeyPath({ generator: (entity: any) => `INV-${entity.year}-${String(entity.number).padStart(4, '0')}` })
  invoiceId!: string;

  year!: number;
  number!: number;
  amount!: number;

  constructor(year: number, number: number, amount: number) {
    this.year = year;
    this.number = number;
    this.amount = amount;
  }
}

const invoice = await db.Invoice.create(new Invoice(2024, 1, 1500.00));
console.log(invoice.invoiceId); // "INV-2024-0001"

Composite Keys

Handle many-to-many relationships with composite keys using the @CompositeKeyPath decorator:

import { CompositeKeyPath } from "idb-ts";

@CompositeKeyPath(['userId', 'projectId'])
@DataClass()
class UserProject {
  userId!: string;
  projectId!: string;

  @Index()
  role!: string;

  joinedAt!: Date;

  constructor(userId: string, projectId: string, role: string) {
    this.userId = userId;
    this.projectId = projectId;
    this.role = role;
    this.joinedAt = new Date();
  }
}

const db = await Database.build("collaboration-db", [UserProject]);

// Create relationships
await db.UserProject.create(new UserProject("user123", "project456", "developer"));
await db.UserProject.create(new UserProject("user123", "project789", "admin"));
await db.UserProject.create(new UserProject("user456", "project456", "viewer"));

// Read with composite key
const relationship = await db.UserProject.read(['user123', 'project456']);
console.log(relationship?.role); // "developer"

// Update relationship
if (relationship) {
  relationship.role = "maintainer";
  await db.UserProject.update(relationship);
}

// Delete with composite key
await db.UserProject.delete(['user123', 'project789']);

// Query by role index
const developers = await db.UserProject.findByIndex('role', 'developer');

Key Generation Utilities

Access key generators directly for your custom logic:

import { KeyGenerators } from "idb-ts";

const uuid = KeyGenerators.uuid();        // Generate UUID
const timestamp = KeyGenerators.timestamp(); // Current timestamp
const random = KeyGenerators.random();    // Random string

πŸ”„ Schema Versioning

idb-ts supports schema versioning to manage database evolution over time. Version your entities and let the library handle automatic migration!

Basic Usage

@DataClass({ version: 1 })
class User {
  @KeyPath() id!: string;
  @Index() email!: string;
  name!: string;
}

@DataClass({ version: 2 })
class Post {
  @KeyPath() id!: string;
  @Index() authorId!: string;
  title!: string;
  content!: string;
}

@DataClass({ version: 3 })
class Comment {
  @KeyPath() id!: string;
  @Index() postId!: string;
  @Index() authorId!: string;
  text!: string;
}

// Database version will be 3 (highest entity version)
const db = await Database.build("blog", [User, Post, Comment]);

console.log(db.getDatabaseVersion()); // 3
console.log(db.getEntityVersions()); // Map with entity versions

Key Features

  • Automatic Version Calculation: Database version = highest entity version
  • Seamless Migration: Only new/updated entities are processed during upgrades
  • Backward Compatibility: Entities without version default to version 1
  • Index Evolution: New indexes are automatically created during migration

Version Management

// Check versions
const dbVersion = db.getDatabaseVersion();
const entityVersions = db.getEntityVersions();
const userVersion = db.getEntityVersion('User');

// Version upgrade flow:
// v1.0: User(v1) β†’ Database v1
// v1.1: User(v1), Post(v2) β†’ Database v2  
// v1.2: User(v1), Post(v2), Comment(v3) β†’ Database v3

πŸ“– Complete Schema Versioning Guide - Detailed documentation with examples and best practices.


πŸ”— Useful Links

πŸŽ‰ Enjoy seamless IndexedDB integration with TypeScript! Happy coding! πŸš€

0