{"id":15041119,"url":"https://github.com/miftahdb/miftahdb","last_synced_at":"2025-09-08T22:43:14.944Z","repository":{"id":255435896,"uuid":"849601354","full_name":"miftahDB/miftahdb","owner":"miftahDB","description":"Fast and lightweight key-value database library","archived":false,"fork":false,"pushed_at":"2025-07-17T15:30:54.000Z","size":839,"stargazers_count":28,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-17T17:55:27.669Z","etag":null,"topics":["database","databases","key-value","key-value-database","kv-storage","kv-store","lightweight","redis","sqlite","sqlite3"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/miftahDB.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-08-29T22:27:17.000Z","updated_at":"2025-07-17T15:30:58.000Z","dependencies_parsed_at":"2024-09-08T09:47:55.841Z","dependency_job_id":"34f2869d-eb54-4ddd-b658-c530fd890382","html_url":"https://github.com/miftahDB/miftahdb","commit_stats":{"total_commits":98,"total_committers":4,"mean_commits":24.5,"dds":0.0714285714285714,"last_synced_commit":"64c9cecf7e38fd9b8cbadde7253a0fe0efe69944"},"previous_names":["miftahdb/miftahdb","miftahdb/miftahdb-node"],"tags_count":47,"template":false,"template_full_name":null,"purl":"pkg:github/miftahDB/miftahdb","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miftahDB%2Fmiftahdb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miftahDB%2Fmiftahdb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miftahDB%2Fmiftahdb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miftahDB%2Fmiftahdb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/miftahDB","download_url":"https://codeload.github.com/miftahDB/miftahdb/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miftahDB%2Fmiftahdb/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274231260,"owners_count":25245659,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-08T02:00:09.813Z","response_time":121,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","databases","key-value","key-value-database","kv-storage","kv-store","lightweight","redis","sqlite","sqlite3"],"created_at":"2024-09-24T20:45:37.259Z","updated_at":"2025-09-08T22:43:14.936Z","avatar_url":"https://github.com/miftahDB.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n\u003ca href=\"https://miftahdb.sqlite3.online/docs/intro/\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://github.com/user-attachments/assets/9c40c2f7-77de-41d3-b5ba-187d4e01746c\" alt=\"MiftahDB Logo\" width=\"148\"\u003e\n\u003c/a\u003e\n\n# MiftahDB\n\n**Fast, Lightweight, Synchronous Key-Value Database for Node.js \u0026 Bun**\n\n[![NPM Version](https://img.shields.io/npm/v/miftahdb?label=NPM\u0026style=flat-square)](https://www.npmjs.com/package/miftahdb)\n[![NPM Type Definitions](https://img.shields.io/npm/types/miftahdb?label=Types\u0026style=flat-square)](https://github.com/miftahDB/miftahDB/blob/main/LICENSE)\n[![NPM Downloads](https://img.shields.io/npm/d18m/miftahdb?label=Downloads\u0026style=flat-square)](https://www.npmjs.com/package/miftahdb)\n[![NPM License](https://img.shields.io/npm/l/miftahdb?label=License\u0026style=flat-square)](https://github.com/miftahDB/miftahDB/blob/main/LICENSE)\n\n[![Release Workflow](https://img.shields.io/github/actions/workflow/status/miftahDB/miftahDB/release.yml?branch=main\u0026label=Release\u0026style=flat-square)](https://github.com/miftahDB/miftahDB/actions/workflows/release.yml)\n[![Bun Tests](https://img.shields.io/github/actions/workflow/status/miftahDB/miftahDB/test-bun.yml?branch=main\u0026label=Bun%20Tests\u0026style=flat-square)](https://github.com/miftahDB/miftahDB/actions/workflows/test-bun.yml)\n[![Node.js Tests](https://img.shields.io/github/actions/workflow/status/miftahDB/miftahDB/test-node.yml?branch=main\u0026label=Node.js%20Tests\u0026style=flat-square)](https://github.com/miftahDB/miftahDB/actions/workflows/test-node.yml)\n[![Lint](https://img.shields.io/github/actions/workflow/status/miftahDB/miftahDB/lint.yml?branch=main\u0026label=Lint\u0026style=flat-square)](https://github.com/miftahDB/miftahDB/actions/workflows/lint.yml)\n[![Format](https://img.shields.io/github/actions/workflow/status/miftahDB/miftahDB/format.yml?branch=main\u0026label=Format\u0026style=flat-square)](https://github.com/miftahDB/miftahDB/actions/workflows/format.yml)\n\n\u003cbr\u003e\n\n\u003cp\u003e\n  \u003ca href=\"https://www.npmjs.com/package/miftahdb\"\u003e\u003cstrong\u003eNPM\u003c/strong\u003e\u003c/a\u003e\n  \u0026nbsp;\u0026nbsp;•\u0026nbsp;\u0026nbsp;\n  \u003ca href=\"https://github.com/miftahDB/benchmarks\"\u003e\u003cstrong\u003eBenchmarks\u003c/strong\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003c/div\u003e\n\n---\n\nMiftahDB offers a high-performance, synchronous key-value storage solution, leveraging the speed of SQLite. It's designed for ease of use in both Node.js (via `better-sqlite3`) and Bun (via `bun:sqlite`) environments, providing a consistent API with robust error handling and TypeScript support.\n\n## Table of Contents\n\n- [✨ Features](#-features)\n- [🚀 Installation](#-installation)\n- [💡 Usage](#-usage)\n  - [Basic Example](#basic-example)\n  - [Synchronous API](#synchronous-api)\n  - [Error Handling](#error-handling)\n- [📚 API Reference](#-api-reference)\n  - [Constructor](#constructor)\n  - [Core Operations](#core-operations)\n    - [`get`](#get)\n    - [`set`](#set)\n    - [`exists`](#exists)\n    - [`delete`](#delete)\n    - [`rename`](#rename)\n  - [Expiration Management](#expiration-management)\n    - [`setExpire`](#setexpire)\n    - [`getExpire`](#getexpire)\n    - [`ttl`](#ttl)\n    - [`persist`](#persist)\n  - [Numeric Operations](#numeric-operations)\n    - [`increment`](#increment)\n    - [`decrement`](#decrement)\n  - [Key Enumeration \u0026 Querying](#key-enumeration--querying)\n    - [`keys`](#keys)\n    - [`pagination`](#pagination)\n    - [`expiredRange`](#expiredrange)\n  - [Counting](#counting)\n    - [`count`](#count)\n    - [`countExpired`](#countexpired)\n  - [Bulk Operations](#bulk-operations)\n    - [`multiGet`](#multiget)\n    - [`multiSet`](#multiset)\n    - [`multiDelete`](#multidelete)\n  - [Database Management](#database-management)\n    - [`cleanup`](#cleanup)\n    - [`vacuum`](#vacuum)\n    - [`flush`](#flush)\n    - [`close`](#close)\n  - [Advanced](#advanced)\n    - [`namespace`](#namespace)\n    - [`execute`](#execute)\n    - [`backup`](#backup)\n    - [`restore`](#restore)\n- [📦 Supported Value Types](#-supported-value-types)\n- [🔍 Pattern Matching](#-pattern-matching)\n- [🔷 TypeScript Typing \u0026 Generics](#-typescript-typing--generics)\n- [⚡ Performance Considerations](#-performance-considerations)\n\n## ✨ Features\n\n- **Fast \u0026 Efficient:** Optimized for speed with SQLite as the backend.\n- **Key Expiration:** Built-in support for automatic key expiration.\n- **Storage Options:** Supports both disk-based and in-memory databases.\n- **Synchronous API:** Designed for simplicity and performance in synchronous workflows.\n- **Dual Runtime Support:**\n  - Node.js: Powered by `better-sqlite3`.\n  - Bun: Utilizes native `bun:sqlite`.\n- **Pattern Matching:** Retrieve keys based on SQL `LIKE` patterns.\n- **Result-Oriented Error Handling:** No `try-catch` needed; methods return a `Result` object.\n- **Namespacing:** Isolate data within logical namespaces.\n- **Atomic Numeric Operations:** `increment` and `decrement` values safely.\n- **TypeScript Native:** Fully typed for a better development experience.\n\n## 🚀 Installation\n\n```bash\n# With NPM\nnpm install miftahdb\n\n# With Bun\nbun add miftahdb\n```\n\n## 💡 Usage\n\nImport based on your runtime:\n\n```javascript\n// For Node.js runtime\nimport { MiftahDB } from \"miftahdb\";\n\n// For Bun runtime\nimport { MiftahDB } from \"miftahdb/bun\";\n```\n\n### Basic Example\n\n```javascript\n// Create or open a database file\nconst db = new MiftahDB(\"my_app_data.db\");\n\n// Set a key-value pair\nconst setResult = db.set(\"user:1\", { name: \"Ahmad Aburob\", city: \"Amman\" });\nif (!setResult.success) {\n  console.error(\"Failed to set key:\", setResult.error.message);\n}\n\n// Get a value\nconst getResult = db.get(\"user:1\");\nif (getResult.success) {\n  console.log(\"User Data:\", getResult.data);\n  // =\u003e User Data: { name: \"Ahmad Aburob\", city: \"Amman\" }\n} else {\n  console.error(\"Failed to get key:\", getResult.error.message);\n}\n\n// Close the database (optional, auto-closes on exit by default)\ndb.close();\n```\n\n### Synchronous API\n\nMiftahDB employs a synchronous API. While often associated with potential blocking in Node.js, for many local database operations, this approach can reduce overhead and simplify code, leading to better performance and concurrency characteristics for common use cases.\n\n### Error Handling\n\nMiftahDB uses a **Result Type** pattern for error handling, eliminating the need for `try-catch` blocks for predictable operational outcomes. Each method returns an object indicating success or failure:\n\n```javascript\nconst result = db.get(\"non_existent_key\");\n\nif (result.success) {\n  // This block won't be reached if the key doesn't exist\n  console.log(\"Data:\", result.data);\n} else {\n  // Handle the error\n  console.error(\"Operation failed:\", result.error.message);\n  // =\u003e Operation failed: Key not found, cannot get.\n}\n```\n\nA `Result` object has the shape:\n`{ success: true, data: YourDataType }` or `{ success: false, error: Error }`.\n\n## 📚 API Reference\n\n### Constructor\n\n`new MiftahDB(path?: string, options?: DBOptions)`\n\nCreates a new MiftahDB instance.\n\n- **Parameters**:\n\n  - `path` (`string`, optional): Path to the database file. Defaults to `\":memory:\"` for an in-memory database.\n  - `options` (`DBOptions`, optional): Configuration for the SQLite connection.\n    - `journalMode` (`string`): Journal mode (default: `\"WAL\"`). Options: `\"DELETE\"`, `\"TRUNCATE\"`, `\"PERSIST\"`, `\"WAL\"`, `\"MEMORY\"`.\n    - `synchronousMode` (`string`): Synchronization mode (default: `\"NORMAL\"`). Options: `\"OFF\"`, `\"NORMAL\"`, `\"FULL\"`, `\"EXTRA\"`.\n    - `tempStoreMode` (`string`): Temporary table storage (default: `\"MEMORY\"`). Options: `\"DEFAULT\"`, `\"MEMORY\"`, `\"FILE\"`.\n    - `cacheSize` (`number`): Suggested N-page cache size (default: `-64000`, approx. 64MB).\n    - `mmapSize` (`number`): Max memory-map size (default: `30000000000`, approx. 28GB).\n    - `lockingMode` (`string`): Locking mode (default: `\"NORMAL\"`). Options: `\"NORMAL\"`, `\"EXCLUSIVE\"`.\n    - `autoVacuumMode` (`string`): Auto-vacuum behavior (default: `\"OFF\"`). Options: `\"OFF\"`, `\"FULL\"`, `\"INCREMENTAL\"`.\n    - `autoCleanupOnClose` (`boolean`): Run `cleanup()` on `close()` (default: `false`).\n    - `autoCloseOnExit` (`boolean`): Close DB on process exit (default: `true`).\n\n- **Example Usage**:\n\n  ```javascript\n  // In-memory database with default options\n  const memDB = new MiftahDB();\n\n  // Disk-based database\n  const fileDB = new MiftahDB(\"path/to/your.db\");\n\n  // Custom configuration\n  const customDB = new MiftahDB(\"custom.db\", {\n    journalMode: \"WAL\",\n    synchronousMode: \"FULL\",\n    cacheSize: -128000, // Approx. 128MB\n  });\n  ```\n\n---\n\n### Core Operations\n\n#### `get`\n\n`get\u003cK extends T\u003e(key: string): Result\u003cK\u003e`\n\nRetrieves a value from the database by its key.\n\n- **Parameters**:\n  - `key` (`string`): The key to look up.\n- **Returns**: `Result\u003cK\u003e` - The operation's result. On success, `data` holds the value.\n- **Throws (via Result.error)**:\n  - `\"Key not found, cannot get.\"`: If the key doesn't exist.\n  - `\"Key expired, cannot get.\"`: If the key existed but was expired (and is then deleted).\n- **Example**:\n  ```typescript\n  type User = { id: number; name: string };\n  const userResult = db.get\u003cUser\u003e(\"user:123\");\n  if (userResult.success) {\n    console.log(userResult.data.name);\n  } else {\n    console.error(userResult.error.message);\n  }\n  ```\n\n#### `set`\n\n`set\u003cK extends T\u003e(key: string, value: K, expiresAt?: Date | number): Result\u003cboolean\u003e`\n\nSets a value in the database, optionally with an expiration time.\n\n- **Parameters**:\n  - `key` (`string`): The key for the value.\n  - `value` (`K`): The value to store.\n  - `expiresAt` (`Date | number`, optional): Expiration time.\n    - `Date`: Absolute expiration time.\n    - `number`: TTL in milliseconds from now.\n- **Returns**: `Result\u003cboolean\u003e` - `data` is `true` on success.\n- **Example**:\n  ```javascript\n  db.set(\"session:xyz\", { userId: 100 }, 3600000); // Expires in 1 hour\n  db.set(\"config\", { theme: \"dark\" }); // No expiration\n  ```\n\n#### `exists`\n\n`exists(key: string): Result\u003cboolean\u003e`\n\nChecks if a key exists and is not expired.\n\n- **Parameters**:\n  - `key` (`string`): The key to check.\n- **Returns**: `Result\u003cboolean\u003e` - `data` is `true` if the key exists and is valid.\n- **Throws (via Result.error)**:\n  - `\"Key not found, cannot check exists.\"`: If the key doesn't exist or is expired.\n- **Note**: Faster than `get()` for simple existence checks due to a more optimized SQL query.\n- **Example**:\n  ```javascript\n  if (db.exists(\"cache:item\").success) {\n    console.log(\"Item is in cache.\");\n  }\n  ```\n\n#### `delete`\n\n`delete(key: string): Result\u003cnumber\u003e`\n\nDeletes a key-value pair.\n\n- **Parameters**:\n  - `key` (`string`): The key to delete.\n- **Returns**: `Result\u003cnumber\u003e` - `data` is the number of rows affected (0 or 1).\n- **Example**:\n  ```javascript\n  const delResult = db.delete(\"old_key\");\n  if (delResult.success) console.log(`Deleted ${delResult.data} items.`);\n  ```\n\n#### `rename`\n\n`rename(oldKey: string, newKey: string): Result\u003cboolean\u003e`\n\nRenames a key. If the new key exists, it's overwritten.\n\n- **Parameters**:\n  - `oldKey` (`string`): The current key name.\n  - `newKey` (`string`): The new key name.\n- **Returns**: `Result\u003cboolean\u003e` - `data` is `true` on success.\n- **Example**:\n  ```javascript\n  db.rename(\"temp_name\", \"permanent_name\");\n  ```\n\n---\n\n### Expiration Management\n\n#### `setExpire`\n\n`setExpire(key: string, expiresAt: Date | number): Result\u003cboolean\u003e`\n\nSets or updates the expiration time for an existing key.\n\n- **Parameters**:\n  - `key` (`string`): The key to update.\n  - `expiresAt` (`Date | number`): New expiration (absolute `Date` or TTL `number` in ms).\n- **Returns**: `Result\u003cboolean\u003e` - `data` is `true` if successful.\n- **Throws (via Result.error)**: If the key doesn't exist, the operation might not change anything or could error depending on internal behavior (current base implementation doesn't throw for \"not found\" here but affects 0 rows).\n- **Example**:\n  ```javascript\n  db.setExpire(\"active_session\", new Date(Date.now() + 60 * 60 * 1000)); // 1 hour from now\n  ```\n\n#### `getExpire`\n\n`getExpire(key: string): Result\u003cDate\u003e`\n\nGets the absolute expiration date of a key.\n\n- **Parameters**:\n  - `key` (`string`): The key to check.\n- **Returns**: `Result\u003cDate\u003e` - `data` is the `Date` object of expiration.\n- **Throws (via Result.error)**:\n  - `\"Key not found, cannot getExpire.\"`\n  - `\"Key has no expiration, cannot getExpire.\"`\n  - `\"Key expired, cannot getExpire.\"` (if found but already expired)\n- **Example**:\n  ```javascript\n  const expResult = db.getExpire(\"my_token\");\n  if (expResult.success)\n    console.log(`Token expires at: ${expResult.data.toLocaleString()}`);\n  ```\n\n#### `ttl`\n\n`ttl(key: string): Result\u003cnumber | null\u003e`\n\nGets the remaining time-to-live (TTL) of a key in milliseconds.\n\n- **Parameters**:\n  - `key` (`string`): The key to check.\n- **Returns**: `Result\u003cnumber | null\u003e` -\n  - `data` is `number`: Remaining TTL in milliseconds.\n  - `data` is `null`: Key exists but has no expiration (persists).\n- **Throws (via Result.error)**:\n  - `\"Key not found, cannot ttl.\"`\n  - `\"Key expired, cannot ttl.\"` (if found but already expired)\n- **Example**:\n  ```javascript\n  const ttlResult = db.ttl(\"session_data\");\n  if (ttlResult.success) {\n    if (ttlResult.data === null) console.log(\"Session persists.\");\n    else console.log(`Session expires in ${ttlResult.data / 1000} seconds.`);\n  }\n  ```\n\n#### `persist`\n\n`persist(key: string): Result\u003cboolean\u003e`\n\nRemoves the expiration from a key, making it persist indefinitely.\n\n- **Parameters**:\n  - `key` (`string`): The key to make persistent.\n- **Returns**: `Result\u003cboolean\u003e` - `data` is `true` if the key was found and made persistent.\n- **Throws (via Result.error)**:\n  - `\"Key not found, cannot persist.\"`\n- **Example**:\n  ```javascript\n  db.persist(\"important_config\");\n  ```\n\n---\n\n### Numeric Operations\n\n#### `increment`\n\n`increment(key: string, amount: number = 1): Result\u003cnumber\u003e`\n\nAtomically increments the numeric value of a key. Initializes to `amount` if key doesn't exist or is expired. Preserves existing valid expiration.\n\n- **Parameters**:\n  - `key` (`string`): The key to increment.\n  - `amount` (`number`, optional): Amount to increment by. Defaults to `1`.\n- **Returns**: `Result\u003cnumber\u003e` - `data` is the new numeric value.\n- **Throws (via Result.error)**:\n  - `\"Increment amount must be a valid number.\"`\n  - If the existing value is not a number.\n- **Example**:\n  ```javascript\n  db.set(\"pageViews\", 100);\n  const newViews = db.increment(\"pageViews\"); // =\u003e { success: true, data: 101 }\n  db.increment(\"newCounter\", 5); // =\u003e { success: true, data: 5 }\n  ```\n\n#### `decrement`\n\n`decrement(key: string, amount: number = 1): Result\u003cnumber\u003e`\n\nAtomically decrements the numeric value of a key. Initializes to `-amount` if key doesn't exist or is expired. Preserves existing valid expiration.\n\n- **Parameters**:\n  - `key` (`string`): The key to decrement.\n  - `amount` (`number`, optional): Amount to decrement by. Defaults to `1`.\n- **Returns**: `Result\u003cnumber\u003e` - `data` is the new numeric value.\n- **Throws (via Result.error)**:\n  - `\"Decrement amount must be a valid number.\"`\n  - If the existing value is not a number.\n- **Example**:\n  ```javascript\n  db.set(\"stockLevel\", 50);\n  const newLevel = db.decrement(\"stockLevel\", 5); // =\u003e { success: true, data: 45 }\n  db.decrement(\"score\", 10); // =\u003e { success: true, data: -10 }\n  ```\n\n---\n\n### Key Enumeration \u0026 Querying\n\n#### `keys`\n\n`keys(pattern: string = \"%\"): Result\u003cstring[]\u003e`\n\nRetrieves keys matching a SQL `LIKE` pattern.\n\n- **Parameters**:\n  - `pattern` (`string`, optional): SQL `LIKE` pattern (e.g., `\"user:%\"`, `\"__log\"`). Defaults to `\"%\"` (all keys).\n- **Returns**: `Result\u003cstring[]\u003e` - `data` is an array of matching keys. Returns an empty array if no matches (success case).\n- **Throws (via Result.error)**:\n  - `\"No keys found, cannot get keys.\"` (Note: current base implementation throws this if result set is empty).\n- **Example**:\n  ```javascript\n  const allKeys = db.keys().data;\n  const userKeys = db.keys(\"user:%\").data;\n  ```\n\n#### `pagination`\n\n`pagination(limit: number, page: number, pattern: string = \"%\"): Result\u003cstring[]\u003e`\n\nRetrieves a paginated list of keys matching a SQL `LIKE` pattern.\n\n- **Parameters**:\n  - `limit` (`number`): Max keys per page.\n  - `page` (`number`): Page number (1-based).\n  - `pattern` (`string`, optional): SQL `LIKE` pattern. Defaults to `\"%\"`\n- **Returns**: `Result\u003cstring[]\u003e` - `data` is an array of keys for the page. Empty if no matches or page out of bounds.\n- **Throws (via Result.error)**:\n  - `\"No keys found, cannot get pagination.\"` (Note: current base implementation throws this if result set is empty for the page).\n- **Example**:\n  ```javascript\n  const pageOne = db.pagination(10, 1, \"product:*\").data;\n  ```\n\n#### `expiredRange`\n\n`expiredRange(start: Date | number, end: Date | number, pattern: string = \"%\"): Result\u003cstring[]\u003e`\n\nRetrieves keys whose expiration falls within a specified date range.\n\n- **Parameters**:\n  - `start` (`Date | number`): Start of the date range (Date object or epoch ms).\n  - `end` (`Date | number`): End of the date range.\n  - `pattern` (`string`, optional): SQL `LIKE` pattern. Defaults to `\"%\"`\n- **Returns**: `Result\u003cstring[]\u003e` - `data` is an array of keys. Empty if no matches.\n- **Throws (via Result.error)**:\n  - `\"No keys found, cannot get expiredRange.\"` (Note: current base implementation throws this if result set is empty).\n- **Example**:\n  ```javascript\n  const expiringSoon = db.expiredRange(Date.now(), Date.now() + 86400000).data; // Expiring in next 24h\n  ```\n\n---\n\n### Counting\n\n#### `count`\n\n`count(pattern: string = \"%\"): Result\u003cnumber\u003e`\n\nCounts keys, optionally matching a pattern.\n\n- **Parameters**:\n  - `pattern` (`string`, optional): SQL `LIKE` pattern. Defaults to `\"%\"`\n- **Returns**: `Result\u003cnumber\u003e` - `data` is the total number of matching keys.\n- **Note**: Faster than `keys(pattern).data.length`.\n- **Example**:\n  ```javascript\n  const totalItems = db.count().data;\n  const imageCount = db.count(\"image:%\").data;\n  ```\n\n#### `countExpired`\n\n`countExpired(pattern: string = \"%\"): Result\u003cnumber\u003e`\n\nCounts currently expired keys, optionally matching a pattern.\n\n- **Parameters**:\n  - `pattern` (`string`, optional): SQL `LIKE` pattern. Defaults to `\"%\"`\n- **Returns**: `Result\u003cnumber\u003e` - `data` is the number of expired keys.\n- **Example**:\n  ```javascript\n  const totalExpired = db.countExpired().data;\n  ```\n\n---\n\n### Bulk Operations\n\n#### `multiGet`\n\n`multiGet\u003cK extends T\u003e(keys: string[]): Result\u003cK[]\u003e`\n\nRetrieves multiple values. Transactional: fails if any key is not found/expired.\n\n- **Parameters**:\n  - `keys` (`string[]`): Array of keys to look up.\n- **Returns**: `Result\u003cK[]\u003e` - `data` is an array of values.\n- **Throws (via Result.error)**:\n  - `\"No keys provided, cannot multiGet.\"`\n  - `\"No keys found, cannot multiGet.\"`\n  - Errors from individual `get` operations.\n- **Example**:\n  ```typescript\n  const items = db.multiGet\u003cProduct\u003e([\"prod:1\", \"prod:2\"]).data;\n  ```\n\n#### `multiSet`\n\n`multiSet\u003cK extends T\u003e(entries: Array\u003c{ key: string; value: K; expiresAt?: Date | number }\u003e): Result\u003cboolean\u003e`\n\nSets multiple key-value pairs. Transactional.\n\n- **Parameters**:\n  - `entries` (`Array`): Array of `{ key, value, expiresAt? }` objects.\n- **Returns**: `Result\u003cboolean\u003e` - `data` is `true` if all set successfully.\n- **Example**:\n  ```javascript\n  db.multiSet([\n    { key: \"a\", value: 1 },\n    { key: \"b\", value: \"two\", expiresAt: 5000 },\n  ]);\n  ```\n\n#### `multiDelete`\n\n`multiDelete(keys: string[]): Result\u003cnumber\u003e`\n\nDeletes multiple keys. Transactional.\n\n- **Parameters**:\n  - `keys` (`string[]`): Array of keys to delete.\n- **Returns**: `Result\u003cnumber\u003e` - `data` is the total number of rows affected.\n- **Throws (via Result.error)**:\n  - `\"No keys provided, cannot multiDelete.\"`\n- **Example**:\n  ```javascript\n  db.multiDelete([\"temp:1\", \"temp:2\"]);\n  ```\n\n---\n\n### Database Management\n\n#### `cleanup`\n\n`cleanup(): Result\u003cnumber\u003e`\n\nRemoves all expired key-value pairs from the database.\n\n- **Returns**: `Result\u003cnumber\u003e` - `data` is the number of rows (expired keys) removed.\n- **Note**: Run periodically to reclaim space and optimize.\n- **Example**:\n  ```javascript\n  const cleanedCount = db.cleanup().data;\n  console.log(`Cleaned ${cleanedCount} expired items.`);\n  ```\n\n#### `vacuum`\n\n`vacuum(): Result\u003cboolean\u003e`\n\nOptimizes the database file by rebuilding it, reducing size and fragmentation.\n\n- **Returns**: `Result\u003cboolean\u003e` - `data` is `true` if successful.\n- **Note**: Can be time-consuming on large databases.\n- **Example**:\n  ```javascript\n  db.vacuum();\n  ```\n\n#### `flush`\n\n`flush(): Result\u003cnumber\u003e`\n\nRemoves all key-value pairs from the database (or current namespace).\n\n- **Returns**: `Result\u003cnumber\u003e` - `data` is the number of rows removed.\n- **Example**:\n  ```javascript\n  db.flush(); // Clears the entire database (or current namespace)\n  ```\n\n#### `close`\n\n`close(): Result\u003cboolean\u003e`\n\nCloses the database connection. Performs pre-close operations like WAL checkpoint and cleanup (if configured).\n\n- **Returns**: `Result\u003cboolean\u003e` - `data` is `true` if successful.\n- **Example**:\n  ```javascript\n  db.close();\n  ```\n\n---\n\n### Advanced\n\n#### `namespace`\n\n`namespace(name: string): IMiftahDB\u003cT\u003e`\n\nCreates a new MiftahDB instance bound to a specific namespace. Keys are automatically prefixed.\n\n- **Parameters**:\n  - `name` (`string`): The namespace identifier.\n- **Returns**: `IMiftahDB\u003cT\u003e` - A new, namespaced MiftahDB instance.\n- **Example**:\n\n  ```javascript\n  const usersDB = db.namespace(\"users\");\n  usersDB.set(\"john\", { email: \"john@example.com\" }); // Key becomes \"users:john\"\n\n  const userPostsDB = usersDB.namespace(\"posts\");\n  userPostsDB.set(\"post1\", { title: \"My First Post\" }); // Key becomes \"users:posts:post1\"\n  ```\n\n#### `execute`\n\n`execute(sql: string, params: unknown[] = []): Result\u003cunknown\u003e`\n\nExecutes a raw SQL statement. Use with caution.\n\n- **Parameters**:\n  - `sql` (`string`): The SQL statement.\n  - `params` (`unknown[]`, optional): Parameters to bind.\n- **Returns**: `Result\u003cunknown\u003e`\n  - For `SELECT`, `data` is an array of rows.\n  - For `INSERT/UPDATE/DELETE`, `data` is a `RunResult` object (from `better-sqlite3`).\n- **Example**:\n  ```javascript\n  const result = db.execute(\n    \"SELECT COUNT(*) as c FROM miftahdb WHERE key LIKE ?\",\n    [\"config:%\"]\n  );\n  if (result.success) console.log(result.data[0].c);\n  ```\n\n#### `backup`\n\n`backup(path: string): PromiseResult\u003cboolean\u003e`\n\nAsynchronously backs up the database to a file.\n\n- **Parameters**:\n  - `path` (`string`): File path for the backup.\n- **Returns**: `PromiseResult\u003cboolean\u003e` - `data` is `true` on success.\n- **Example**:\n  ```javascript\n  await db.backup(\"mydb.backup.db\");\n  ```\n\n#### `restore`\n\n`restore(path: string): PromiseResult\u003cboolean\u003e`\n\nAsynchronously restores the database from a backup file, replacing current content.\n\n- **Parameters**:\n  - `path` (`string`): Path to the backup file.\n- **Returns**: `PromiseResult\u003cboolean\u003e` - `data` is `true` on success.\n- **Example**:\n  ```javascript\n  await db.restore(\"mydb.backup.db\");\n  ```\n\n---\n\n## 📦 Supported Value Types\n\nMiftahDB can store various JavaScript data types. Internally, values are serialized using `msgpack-lite` or stored as raw binary data.\n\n| No. | Type                  | Storable? | Notes                                                        |\n| --- | --------------------- | :-------: | ------------------------------------------------------------ |\n| 1   | String                |    ✅     |                                                              |\n| 2   | Number                |    ✅     | Includes `NaN`, `Infinity`, `-Infinity`.                     |\n| 3   | Boolean               |    ✅     |                                                              |\n| 4   | Array                 |    ✅     | Elements must also be storable.                              |\n| 5   | Record (Plain Object) |    ✅     | Values must also be storable.                                |\n| 6   | Date                  |    ✅     | Stored as MessagePack timestamp; retrieved as `Date` object. |\n| 7   | Buffer (Node.js)      |    ✅     | Stored as raw binary with a type marker.                     |\n| 8   | Uint8Array            |    ✅     | Stored as raw binary with a type marker.                     |\n| 9   | Null                  |    ✅     |                                                              |\n| 10  | `undefined`           |    ⚠️     | Stored as `null`.                                            |\n\n**Example for core types:**\n\n```javascript\ndb.set(\"myString\", \"Hello Miftah!\");\ndb.set(\"myNumber\", 123.45);\ndb.set(\"myBoolean\", true);\ndb.set(\"myArray\", [1, \"two\", { three: 3 }]);\ndb.set(\"myRecord\", { user: \"guest\", score: 0 });\ndb.set(\"myDate\", new Date());\ndb.set(\"myBuffer\", Buffer.from(\"binary data\"));\ndb.set(\"myUint8Array\", new Uint8Array([0, 1, 2]));\ndb.set(\"myNull\", null);\n```\n\n## 🔍 Pattern Matching\n\nSeveral MiftahDB methods support SQL `LIKE` patterns for key matching: `keys()`, `pagination()`, `count()`, `countExpired()`, `expiredRange()`.\n\n- `%`: Matches any sequence of zero or more characters.\n- `_`: Matches exactly one character.\n\n**Examples**:\n\n```javascript\n// Keys starting with \"session:\"\nconst sessionKeys = db.keys(\"session:%\").data;\n\n// Keys ending with \"_log\"\nconst logKeys = db.keys(\"%_log\").data;\n\n// Keys with exactly 5 characters\nconst fiveCharKeys = db.keys(\"_____\").data;\n\n// Keys like \"user:???:data\" (e.g., user:123:data)\nconst specificUserKeys = db.keys(\"user:___:data\").data;\n```\n\n## 🔷 TypeScript Typing \u0026 Generics\n\nMiftahDB is written in TypeScript and provides strong typing for all methods. Use generics to specify the expected type of your data:\n\n```typescript\ntype UserProfile = {\n  id: string;\n  username: string;\n  email?: string;\n};\n\n// Set a strongly-typed value\ndb.set\u003cUserProfile\u003e(\"user:profile:jane\", {\n  id: \"jane_doe\",\n  username: \"JaneD\",\n});\n\n// Retrieve with type safety\nconst profileResult = db.get\u003cUserProfile\u003e(\"user:profile:jane\");\nif (profileResult.success) {\n  console.log(profileResult.data.username); // Autocompletion and type checking!\n}\n\n// Multi-Set with types\ndb.multiSet\u003cUserProfile | null\u003e([\n  // Can store different types or null\n  { key: \"user:profile:john\", value: { id: \"john_d\", username: \"JohnD\" } },\n  { key: \"user:profile:guest\", value: null }, // Storing null explicitly\n]);\n\n// Multi-Get with types\nconst profilesResult = db.multiGet\u003cUserProfile\u003e([\n  \"user:profile:jane\",\n  \"user:profile:john\",\n]);\nif (profilesResult.success) {\n  profilesResult.data.forEach((profile) =\u003e console.log(profile.id));\n}\n```\n\n## ⚡ Performance Considerations\n\nMiftahDB is built for speed:\n\n1.  **Synchronous Operations:** Reduces Promise/async overhead for local DB access.\n2.  **Optimized SQLite Backend:** Leverages `better-sqlite3` (Node.js) and `bun:sqlite` (Bun), both known for high performance.\n3.  **Efficient Queries:** Uses specific SQL queries optimized for key-value operations (e.g., `EXISTS` for `exists()`).\n4.  **In-Memory Mode:** Offers `\":memory:\"` for maximum throughput for caches or temporary data.\n\n**Tips for Best Performance:**\n\n- **In-Memory for Speed:** Use `:memory:` databases for transient data or caches where persistence across restarts isn't required.\n- **Batch Operations:** Utilize `multiSet()`, `multiGet()`, and `multiDelete()` for multiple items to reduce overhead of individual calls.\n- **Periodic Maintenance:**\n  - Run `cleanup()` regularly to remove expired keys and free up space.\n  - Run `vacuum()` occasionally (especially after large deletions) to compact the database file and improve query performance. This can be a blocking operation.\n- **Appropriate PRAGMAs:** While defaults are good, advanced users can tweak SQLite PRAGMA settings via the constructor options for specific workloads.\n- **Avoid Over-Fetching:** Use `exists()` instead of `get()` if you only need to check for presence. Use `count()` instead of `keys().length`.\n\n---\n\nContributions, issues, and feature requests are welcome!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmiftahdb%2Fmiftahdb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmiftahdb%2Fmiftahdb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmiftahdb%2Fmiftahdb/lists"}