### Install Ramify JS React Hooks Package Source: https://ramifyjs.haroonwaves.com/docs/getting-started Install the optional Ramify JS React hooks package if you are using React and need live query observation with the `useLiveQuery` hook. ```bash npm install @ramifyjs/react-hooks ``` ```bash pnpm add @ramifyjs/react-hooks ``` ```bash yarn add @ramifyjs/react-hooks ``` -------------------------------- ### Install Ramify JS Core Package Source: https://ramifyjs.haroonwaves.com/docs/getting-started Install the core Ramify JS package using npm, pnpm, or yarn. This package is environment-agnostic. ```bash npm install @ramifyjs/core ``` ```bash pnpm add @ramifyjs/core ``` ```bash yarn add @ramifyjs/core ``` -------------------------------- ### Starting a Query with .where() Source: https://ramifyjs.haroonwaves.com/docs/api/query Initiate a query by targeting a specific field or providing a set of criteria for matching documents. ```APIDOC ## Starting a Query ### `where(field)` Target a specific field for filtering operations. **Parameters:** - **`field`** (K extends keyof T) - The field name to query **Returns:** `WhereStage` - A query stage with filtering operators ### `where(criteria)` Match fields by strict equality (deep equality for arrays). **Parameters:** - **`criteria`** (Criteria) - An object with field-value pairs to match **Returns:** `ExecutableStage` - An executable query stage **Example:** ```javascript // Targeting a specific field db.users.where('email').equals('alice@example.com'); // Matching by criteria db.users.where({ status: 'active', roles: ['admin'] }); ``` ``` -------------------------------- ### Querying Multiple Collections with useLiveQuery Source: https://ramifyjs.haroonwaves.com/docs/api/react-hooks Example demonstrating how to query data from multiple collections (`db.users` and `db.messages`) within a single `useLiveQuery` callback. It also shows how to include external dependencies like `userId` in the `others` array. ```javascript function UserMessages({ userId }: { userId: string }) { const data = useLiveQuery( () => { const user = db.users.get(userId); const messages = db.messages.where('senderId').equals(userId).toArray(); return { user, messages }; }, { collections: [db.users, db.messages], // Subscribe to both collections others: [userId], } ); return (

{data?.user?.name}

Messages: {data?.messages?.length ?? 0}

{data?.messages?.map((message) => (
{message.content}
))}
); } ``` -------------------------------- ### Start a query with object criteria for equality matching Source: https://ramifyjs.haroonwaves.com/docs/api/collection Use `where(criteria)` to start a query using an object where keys are field names and values are the criteria for equality matching. Array values for a field will act as an `IN` operator. ```javascript // Object criteria db.users.where({ age: 18, role: 'admin' }); ``` ```javascript // Array values act as IN operator db.users.where({ status: ['active', 'pending'] }); ``` -------------------------------- ### Start Query by Field Source: https://ramifyjs.haroonwaves.com/docs/api/query Target a specific field for filtering operations. Use this when you know the exact field you want to query. ```javascript db.users.where('email').equals('alice@example.com'); ``` -------------------------------- ### Execute Query and Get All Results Source: https://ramifyjs.haroonwaves.com/docs/api/query Terminate the query chain and retrieve all matching documents as an array. ```javascript const activeUsers = db.users.where({ status: 'active' }).toArray(); ``` -------------------------------- ### Reactive Query for Active Users Source: https://ramifyjs.haroonwaves.com/docs/api/react-hooks A usage example of `useLiveQuery` to display a list of active users, updating automatically when the `db.users` collection changes. The `others` array is empty as no external dependencies are used. ```javascript function ActiveUsers() { const activeUsers = useLiveQuery(() => db.users.where({ status: 'active' }).toArray(), { collections: [db.users], others: [], }); return (

Active Users: {activeUsers?.length ?? 0}

{activeUsers?.map((user) => (
{user.name}
))}
); } ``` -------------------------------- ### Start Query by Criteria Object Source: https://ramifyjs.haroonwaves.com/docs/api/query Match fields by strict equality using an object of field-value pairs. This is useful for applying multiple filters at once. ```javascript // Exact match db.users.where({ status: 'active', roles: ['admin'] }); ``` -------------------------------- ### Start a query by field for indexed lookups Source: https://ramifyjs.haroonwaves.com/docs/api/collection Use `where(field)` to begin a query chain targeting a specific indexed field. This is more efficient for indexed fields than `filter()`. ```javascript // Property match db.users.where('age').equals(18); ``` -------------------------------- ### Get all primary keys from a collection Source: https://ramifyjs.haroonwaves.com/docs/api/collection Use `keys()` to retrieve an array of all primary keys present in the collection. This method takes no arguments. ```javascript const userIds = db.users.keys(); ``` -------------------------------- ### Retrieve a document by its primary key Source: https://ramifyjs.haroonwaves.com/docs/api/collection Use `get()` to fetch a single document using its primary key. Returns `undefined` if the document is not found. ```javascript const user = db.users.get('1'); if (user) { console.log(user.name); } ``` -------------------------------- ### Execute Query and Get Count Source: https://ramifyjs.haroonwaves.com/docs/api/query Terminate the query chain and retrieve the total number of matching documents. ```javascript const activeCount = db.users.where({ status: 'active' }).count(); ``` -------------------------------- ### Execute Query and Get First Result Source: https://ramifyjs.haroonwaves.com/docs/api/query Terminate the query chain and retrieve only the first matching document. Returns `undefined` if no documents match. ```javascript const firstAdmin = db.users.where('roles').anyOf(['admin']).first(); ``` -------------------------------- ### Count documents in a collection Source: https://ramifyjs.haroonwaves.com/docs/api/collection Use `count()` to get the total number of documents in a collection. This method requires no parameters. ```javascript const totalUsers = db.users.count(); ``` -------------------------------- ### Collection Bulk Operations Source: https://ramifyjs.haroonwaves.com/docs/api/collection Provides methods for performing bulk operations (add, put, get, update, delete) on multiple documents within a collection. ```APIDOC ## POST /api/collection/{collectionId}/bulk/add ### Description Adds multiple documents to the collection. Throws if any document with the same primary key exists. ### Method POST ### Endpoint `/api/collection/{collectionId}/bulk/add` ### Parameters #### Path Parameters - **collectionId** (string) - Required - The ID of the collection. #### Request Body - **documents** (array) - Required - Array of documents to add. - Each element is an object representing a document with an `id` field. ### Request Example ```json [ { "id": "1", "name": "Alice" }, { "id": "2", "name": "Bob" } ] ``` ### Response #### Success Response (200) - **primaryKeys** (array) - Array of primary keys of the added documents. #### Response Example ```json [ "1", "2" ] ``` ``` ```APIDOC ## POST /api/collection/{collectionId}/bulk/put ### Description Adds or updates multiple documents in the collection. ### Method POST ### Endpoint `/api/collection/{collectionId}/bulk/put` ### Parameters #### Path Parameters - **collectionId** (string) - Required - The ID of the collection. #### Request Body - **documents** (array) - Required - Array of documents to add or update. - Each element is an object representing a document with an `id` field. ### Request Example ```json [ { "id": "1", "name": "Alice Updated" }, { "id": "2", "name": "Bob Updated" } ] ``` ### Response #### Success Response (200) - **primaryKeys** (array) - Array of primary keys of the documents. #### Response Example ```json [ "1", "2" ] ``` ``` ```APIDOC ## POST /api/collection/{collectionId}/bulk/get ### Description Retrieves multiple documents by their primary keys. ### Method POST ### Endpoint `/api/collection/{collectionId}/bulk/get` ### Parameters #### Path Parameters - **collectionId** (string) - Required - The ID of the collection. #### Request Body - **keys** (array) - Required - Array of primary keys to retrieve. ### Request Example ```json [ "1", "2", "3" ] ``` ### Response #### Success Response (200) - **documents** (array) - Array of documents (or `undefined` for not found). #### Response Example ```json [ { "id": "1", "name": "Alice" }, { "id": "2", "name": "Bob" }, undefined ] ``` ``` ```APIDOC ## POST /api/collection/{collectionId}/bulk/update ### Description Updates multiple documents with their respective changes. ### Method POST ### Endpoint `/api/collection/{collectionId}/bulk/update` ### Parameters #### Path Parameters - **collectionId** (string) - Required - The ID of the collection. #### Request Body - **updates** (array) - Required - Array of objects, each containing a `key` and `changes`. - **key** (string) - Required - The primary key of the document to update. - **changes** (object) - Required - An object containing the fields to update. ### Request Example ```json [ { "key": "1", "changes": {"status": "inactive"} }, { "key": "2", "changes": {"status": "active"} } ] ``` ### Response #### Success Response (200) - **results** (array) - Array of primary keys (or `undefined` for not found). #### Response Example ```json [ "1", "2" ] ``` ``` ```APIDOC ## POST /api/collection/{collectionId}/bulk/delete ### Description Deletes multiple documents by their primary keys. ### Method POST ### Endpoint `/api/collection/{collectionId}/bulk/delete` ### Parameters #### Path Parameters - **collectionId** (string) - Required - The ID of the collection. #### Request Body - **keys** (array) - Required - Array of primary keys to delete. ### Request Example ```json [ "1", "2", "3" ] ``` ### Response #### Success Response (200) - **results** (array) - Array of deleted primary keys (or `undefined` for not found). #### Response Example ```json [ "1", "2", undefined ] ``` ``` -------------------------------- ### Execute Query and Get Last Result Source: https://ramifyjs.haroonwaves.com/docs/api/query Terminate the query chain and retrieve only the last matching document. Returns `undefined` if no documents match. Requires sorting to be meaningful. ```javascript const lastUser = db.users.where({ status: 'active' }).sortBy('createdAt').last(); ``` -------------------------------- ### Query Data in Ramify JS Collections Source: https://ramifyjs.haroonwaves.com/docs/getting-started Retrieve data using various query methods like `get`, `toArray`, `filter`, `where`, `sortBy`, and `limit`. Use `toArray` with caution on large datasets. ```typescript // Get a user by ID const user = db.users.get('1'); // Get all users const allUsers = db.users.toArray(); // Collection filter (use with caution for large datasets) const adults = db.users.filter((user) => user.age >= 18).toArray(); // Query with multi-entry index const developers = db.users.where('roles').equals(['admin']).toArray(); // Complex queries with sorting and pagination const topUsers = db.users .where('roles') .anyOf(['admin', 'manager']) .sortBy('name') .limit(10) .toArray(); ``` -------------------------------- ### Define Store with Indexes Source: https://ramifyjs.haroonwaves.com/docs/core/indexes Configure your store schema with primary key, secondary indexes, and multi-entry indexes during store creation. Indexes must be defined upfront. ```javascript const db = ramify.createStore({ users: { primaryKey: 'id', indexes: ['email', 'active', 'stats.level'], // Single field indexes multiEntry: ['roles'], // Multi-entry indexes (arrays) }, }); ``` -------------------------------- ### Usage Patterns Source: https://ramifyjs.haroonwaves.com/docs/api/react-hooks Illustrates common ways to use the `useLiveQuery` hook for different data fetching scenarios. ```APIDOC ### Reactive Query Query all documents matching a criteria and reactively update when the collection changes. ```javascript function ActiveUsers() { const activeUsers = useLiveQuery(() => db.users.where({ status: 'active' }).toArray(), { collections: [db.users], others: [], }); return (

Active Users: {activeUsers?.length ?? 0}

{activeUsers?.map((user) => (
{user.name}
))}
); } ``` ### Multiple Collections Query across multiple collections and subscribe to all of them. ```javascript function UserMessages({ userId }: { userId: string }) { const data = useLiveQuery( () => { const user = db.users.get(userId); const messages = db.messages.where('senderId').equals(userId).toArray(); return { user, messages }; }, { collections: [db.users, db.messages], // Subscribe to both collections others: [userId], } ); return (

{data?.user?.name}

Messages: {data?.messages?.length ?? 0}

{data?.messages?.map((message) => (
{message.content}
))}
); } ``` ``` -------------------------------- ### Ramify Initialization Source: https://ramifyjs.haroonwaves.com/docs/api/store Initializes a new Ramify instance. This is the entry point for interacting with the Store API. ```APIDOC ## Initialize Ramify Instance ### Description Creates a new Ramify instance. This instance serves as the central database manager. ### Method `new Ramify()` ### Parameters None ### Returns A new `Ramify` instance. ### Request Example ```typescript import { Ramify } from '@ramifyjs/core'; const ramify = new Ramify(); ``` ``` -------------------------------- ### Query Entry Points Source: https://ramifyjs.haroonwaves.com/docs/api/collection Methods to initiate query chains for filtering and ordering documents. ```APIDOC ## where(field) ### Description Starts a query execution chain targeting a specific field for indexed queries. ### Method N/A (Method call on collection object) ### Endpoint N/A ### Parameters #### Path Parameters - **field** (K extends keyof T) - Required - The field name to query. ### Request Example ```javascript // Property match db.users.where('age').equals(18); ``` ### Response #### Success Response (WhereStage) - **queryStage** (WhereStage) - A query stage object with filtering operators. ### Response Example (Returns a query stage object, not a direct value) --- ## where(criteria) ### Description Starts a query execution chain with object criteria for equality matching. ### Method N/A (Method call on collection object) ### Endpoint N/A ### Parameters #### Path Parameters - **criteria** (Criteria) - Required - An object with field-value pairs to match. Array values act as the `IN` operator. ### Request Example ```javascript // Object criteria db.users.where({ age: 18, role: 'admin' }); // Array values act as IN operator db.users.where({ status: ['active', 'pending'] }); ``` ### Response #### Success Response (ExecutableStage) - **queryStage** (ExecutableStage) - An executable query stage. ### Response Example (Returns a query stage object, not a direct value) --- ## filter(callback) ### Description Filters documents using a JavaScript callback function. This method iterates through all documents and is generally slower than indexed queries. ### Method N/A (Method call on collection object) ### Endpoint N/A ### Parameters #### Path Parameters - **callback** ((document: T) => boolean) - Required - Predicate function to filter documents. ### Request Example ```javascript db.users.filter((u) => u.name.startsWith('A')); ``` ### Response #### Success Response (ExecutableStage) - **queryStage** (ExecutableStage) - An executable query stage. ### Response Example (Returns a query stage object, not a direct value) --- ## sortBy(field) ### Description Returns a query ordered by the specified field. This performs JavaScript sorting internally. ### Method N/A (Method call on collection object) ### Endpoint N/A ### Parameters #### Path Parameters - **field** (keyof T) - Required - The field to order by. ### Request Example ```javascript db.users.sortBy('name').toArray(); ``` ### Response #### Success Response (OrderableStage) - **queryStage** (OrderableStage) - An orderable query stage. ### Response Example (Returns a query stage object, not a direct value) --- ## limit(n) ### Description Returns a query with a limit applied, restricting the number of results. ### Method N/A (Method call on collection object) ### Endpoint N/A ### Parameters #### Path Parameters - **count** (number) - Required - Maximum number of results to return. ### Request Example ```javascript db.users.limit(10).toArray(); ``` ### Response #### Success Response (LimitedStage) - **queryStage** (LimitedStage) - A limited query stage. ### Response Example (Returns a query stage object, not a direct value) --- ## offset(n) ### Description Returns a query with an offset applied, skipping a specified number of results. ### Method N/A (Method call on collection object) ### Endpoint N/A ### Parameters #### Path Parameters - **count** (number) - Required - Number of results to skip. ### Request Example ```javascript db.users.limit(10).offset(5).toArray(); ``` ### Response #### Success Response (LimitedStage) - **queryStage** (LimitedStage) - A limited query stage. ### Response Example (Returns a query stage object, not a direct value) ``` -------------------------------- ### Performance Tips Source: https://ramifyjs.haroonwaves.com/docs/api/query Provides recommendations for optimizing query performance. ```APIDOC ## Performance Tips * **Use indexed queries** – Queries on indexed fields are significantly faster than `filter()`. * **Order matters** – Apply indexed filters first, then use `filter()` for additional criteria. * **Limit early** – Use `limit()` to reduce the number of documents processed. * **Multi-entry indexes** – Use `allOf()` for array fields with multi-entry indexes. ``` -------------------------------- ### Tokenize and Write Product Data Source: https://ramifyjs.haroonwaves.com/docs/guides/search Implement a function to tokenize product names into an array of search terms and save the product with these terms in the `_searchTerms` field. ```javascript function saveProduct(product) { // Simple tokenizer: split by space, lowercase const terms = product.name.toLowerCase().split(/\s+/); db.products.put({ ...product, _searchTerms: terms, }); } ``` -------------------------------- ### Retrieve all documents in a collection Source: https://ramifyjs.haroonwaves.com/docs/api/collection Use `toArray()` to get all documents currently stored in the collection as an array. Useful for iterating or counting all items. ```javascript const allUsers = db.users.toArray(); console.log(`Total users: ${allUsers.length}`); ``` -------------------------------- ### Use Live Query Hook in React Source: https://ramifyjs.haroonwaves.com/docs/api/react-hooks Demonstrates how to use the `useLiveQuery` hook to fetch and reactively update data from the database. Ensure all queried collections are listed in the `collections` dependency array to guarantee updates. ```javascript import { useLiveQuery } from '@ramifyjs/react-hooks'; function MyComponent() { const data = useLiveQuery( () => { // Your query logic here return db.users.where('status').equals('active').toArray(); }, { // Dependencies to watch for database changes collections: [db.users], // Other React dependencies (like props or state) others: [], } ); return
{data?.length}
; } ``` -------------------------------- ### Create Store Source: https://ramifyjs.haroonwaves.com/docs/api/store Defines the database schema and creates collections within the Ramify instance. It infers document types and primary keys from the provided schema definition. ```APIDOC ## Create Store ### Description Defines the database schema and creates collections. This method infers document types and primary keys from the schema definition. ### Method `createStore(storeDefinition)` ### Parameters #### Request Body - **`storeDefinition`** (`S`) - An object mapping collection names to their schema definition. - **`primaryKey`** (`Pk extends keyof T`) - The field used as the unique identifier (required). - **`indexes`** (`Array>`) - Array of fields to be indexed for fast lookups. - **`multiEntry`** (`Array>`) - Array of array-fields where each element should be indexed. ### Returns A typed store object where: * The store extends `Ramify` with inferred document types. * Each collection is accessible as a property with type `Collection`. ### Request Example ```typescript import { Ramify, type Schema } from '@ramifyjs/core'; // Assuming User and Message types are defined elsewhere // type User = { id: string; email: string; ... }; // type Message = { id: string; senderId: string; ... }; const ramify = new Ramify(); const db = ramify.createStore<{ users: Schema; messages: Schema; }>({ users: { primaryKey: 'id', indexes: ['email', 'status', 'stats.level'], multiEntry: ['roles'], }, messages: { primaryKey: 'id', indexes: ['senderId', 'channelId', 'metadata.priority'], multiEntry: ['mentions', 'tags', 'metadata.readBy'], }, }); // db.users is now typed as Collection // db.messages is now typed as Collection ``` ``` -------------------------------- ### Initialize Ramify Store with Collections and Schema Source: https://ramifyjs.haroonwaves.com/docs/core/store-and-collections Initialize Ramify and create a typed store with defined collections, primary keys, indexes, and multi-entry fields. Ensure Ramify is imported before use. ```typescript import { Ramify, type Schema } from '@ramifyjs/core'; // Initialize Ramify const ramify = new Ramify(); // Create a store with collections and schema const db = ramify.createStore({ users: { primaryKey: 'id', indexes: ['email', 'active', 'stats.level'], multiEntry: ['roles'], }, }); // db.users is now your typed collection ``` -------------------------------- ### Initialize Ramify Instance Source: https://ramifyjs.haroonwaves.com/docs/api/store Creates a new Ramify instance to manage the database. No parameters are required. ```typescript import { Ramify, type Schema } from '@ramifyjs/core'; const ramify = new Ramify(); ``` -------------------------------- ### Create a Ramify JS Store with Schemas Source: https://ramifyjs.haroonwaves.com/docs/getting-started Instantiate Ramify JS and define your collections with their respective schemas, specifying primary keys, indexes, and multi-entry fields. ```typescript import { Ramify, type Schema } from '@ramifyjs/core'; const db = new Ramify().createStore({ users: { primaryKey: 'id', indexes: ['email', 'status', 'stats.level'], multiEntry: ['roles'], }, messages: { primaryKey: 'id', indexes: ['senderId', 'channelId', 'metadata.priority'], multiEntry: ['mentions', 'tags', 'metadata.readBy'], }, }); ``` -------------------------------- ### Retrieve multiple documents by their primary keys Source: https://ramifyjs.haroonwaves.com/docs/api/collection Use `bulkGet()` to fetch multiple documents efficiently by providing an array of their primary keys. Returns an array with documents or `undefined` for any keys not found. ```javascript const users = db.users.bulkGet(['1', '2', '3']); ``` -------------------------------- ### Implement Incremental Sync with External DB Source: https://ramifyjs.haroonwaves.com/docs/guides/persistence Set up Ramify JS, subscribe to document changes, and sync them with an external database. Handle create, update, delete, and clear operations. Wrap persistence operations in try/catch blocks to manage potential errors and ensure data consistency. ```typescript import { Ramify, Schema } from '@ramifyjs/core'; // 1. Setup Ramify JS const ramify = new Ramify(); const db = ramify.createStore({ users: { primaryKey: 'id', indexes: ['email'] }, }); // 2. Incremental Sync Logic db.users.subscribe(async (type, keys) => { try { switch (type) { case 'create': case 'update': const docs = db.users.bulkGet(keys); await myExternalDB.bulkPut('users', docs); break; case 'delete': await myExternalDB.bulkDelete('users', keys); break; case 'clear': await myExternalDB.clear('users'); break; } } catch (error) { console.error('Persistence failed:', error); // IMPORTANT: If persistence fails, you may need to update/revert // the stale data in Ramify JS to keep it in sync with your storage. } }); // 3. Initial Hydration (Do it as batch if dataset is large) const storedUsers = await myExternalDB.getAll('users'); db.users.bulkAdd(storedUsers); ``` -------------------------------- ### Build AND Condition Query Source: https://ramifyjs.haroonwaves.com/docs/core/queries Combine exact field matches with `.where({ field: value })` and manual filters using `.filter()` for complex AND logic. This is useful when one condition requires an index and another requires arbitrary logic. ```javascript // AND condition: using exact match for multiple fields const special = db.messages .where({ channelId: 'h9asa09ajh38' }) // exact match .filter((m) => m.metadata.readBy.length > 0) // manual filter for complex AND logic .toArray(); ``` -------------------------------- ### Build OR Condition Query Source: https://ramifyjs.haroonwaves.com/docs/core/queries Use `.where('field').anyOf(['value1', 'value2'])` to retrieve documents where the specified field matches any of the provided values. This requires the field to be indexed. ```javascript // OR condition: using anyOf for single field const adminsOrMods = db.messages.where('metadata.priority').anyOf(['high', 'normal']).toArray(); ``` -------------------------------- ### Multi-Entry Indexing for Roles Source: https://ramifyjs.haroonwaves.com/docs/guides/search Utilize Ramify's `multiEntry` index to search for strict keywords or roles within a collection. This is effective for exact or any-of matches. ```javascript // Find all users with role only 'manager' const managers = db.users.where('roles').equals(['manager']).toArray(); // Find all users with role 'admin' const admins = db.users.where('roles').anyOf(['admin']).toArray(); // Find all users with role 'user' plus 'reader' const usersWithReadAccess = db.users.where('roles').allOf(['user', 'reader']).toArray(); ``` -------------------------------- ### Define Product Schema with Multi-Entry Index Source: https://ramifyjs.haroonwaves.com/docs/guides/search Define a schema for products, including a `_searchTerms` field intended for tokenized search. This field is configured as a `multiEntry` index. ```javascript interface Product { id: string; name: string; // Computed field for search _searchTerms: string[]; } const db = ramify.createStore<{ products: Schema }>({ products: { primaryKey: 'id', multiEntry: ['_searchTerms'], }, }); ``` -------------------------------- ### Offset Pagination Source: https://ramifyjs.haroonwaves.com/docs/guides/pagination-sorting Implement traditional page-based UIs using `limit()` and `offset()`. Be cautious with large offsets as Ramify JS must iterate through all offset records, impacting performance. ```javascript // First page (10 items) const page1 = db.users.sortBy('id').limit(10).offset(0).toArray(); ``` ```javascript // Second page const page2 = db.users.sortBy('id').limit(10).offset(10).toArray(); ``` ```javascript // With filtering const activePage1 = db.users .where({ status: 'active' }) .sortBy('createdAt') .limit(20) .offset(0) .toArray(); ``` -------------------------------- ### useLiveQuery Hook Source: https://ramifyjs.haroonwaves.com/docs/api/react-hooks The `useLiveQuery` hook allows functional components to reactively update when database content changes. It executes a callback function immediately and re-executes it whenever specified dependencies change. ```APIDOC ## `useLiveQuery(callback, dependencies)` ### Description Executes the callback immediately and re-executes it whenever the dependent collections change. ### Parameters #### `callback` - **Type**: `() => T` - **Description**: A synchronous function that queries the database. It runs on mount and whenever dependencies change. It should return the query result. **Performance Note**: The callback runs on every render and every database change. Keep it fast. For expensive transformations, use `useMemo` on the query result rather than in the callback. #### `dependencies` - **Type**: `{ collections: readonly Subscribable[]; others: readonly unknown[] }` - **Description**: An object containing arrays of dependencies to observe. - **`collections`** (`readonly Subscribable[]`): An array of collections to observe. When these collections emit a change (add/update/delete), the hook re-runs the callback. **Requirement**: Must include all collections queried in the callback. If a collection is omitted, the component won't update when that collection changes. - **`others`** (`readonly unknown[]`): An array of standard React dependencies (like `useEffect` deps). If these change, the hook also re-runs. Include props, state, or other values used in the callback. ### Returns - **Type**: `T | null` - **Description**: Returns the result of the callback. Returns `null` during initial mount if the callback hasn't executed yet. Typically returns synchronously, so `null` is rare in practice. ### Example ```javascript import { useLiveQuery } from '@ramifyjs/react-hooks'; function MyComponent() { const data = useLiveQuery( () => { // Your query logic here return db.users.where('status').equals('active').toArray(); }, { // Dependencies to watch for database changes collections: [db.users], // Other React dependencies (like props or state) others: [], } ); return
{data?.length}
; } ``` ``` -------------------------------- ### Execution Methods Source: https://ramifyjs.haroonwaves.com/docs/api/query Terminate the query chain and retrieve the results. ```APIDOC ## Execution Methods ### `toArray()` Returns all matching documents as an array. **Parameters:** None **Returns:** `T[]` - Array of matching documents ### `first()` Returns the first matching document. **Parameters:** None **Returns:** `T | undefined` - The first matching document, or `undefined` if no matches ### `last()` Returns the last matching document. **Parameters:** None **Returns:** `T | undefined` - The last matching document, or `undefined` if no matches ### `count()` Returns the number of matching documents. **Parameters:** None **Returns:** `number` - The count of matching documents **Example:** ```javascript // Get all active users const activeUsers = db.users.where({ status: 'active' }).toArray(); // Get the first user with 'admin' role const firstAdmin = db.users.where('roles').anyOf(['admin']).first(); // Get the last user sorted by creation date const lastUser = db.users.where({ status: 'active' }).sortBy('createdAt').last(); // Count active users const activeCount = db.users.where({ status: 'active' }).count(); ``` ``` -------------------------------- ### Define Store Schema and Create Collections Source: https://ramifyjs.haroonwaves.com/docs/api/store Defines the database schema and creates collections. This method infers document types and primary keys from the schema definition. Ensure primary keys and indexes are correctly specified. ```typescript const db = ramify.createStore({ users: { primaryKey: 'id', indexes: ['email', 'status', 'stats.level'], multiEntry: ['roles'], }, messages: { primaryKey: 'id', indexes: ['senderId', 'channelId', 'metadata.priority'], multiEntry: ['mentions', 'tags', 'metadata.readBy'], }, }); // db.users is now typed as Collection // db.messages is now typed as Collection ``` -------------------------------- ### Subscribe to collection changes Source: https://ramifyjs.haroonwaves.com/docs/api/collection Use `subscribe(callback)` to listen for changes (create, update, delete, clear) in the collection. The callback receives the operation type and affected keys. Remember to call the returned unsubscribe function to prevent memory leaks. ```javascript const unsubscribe = db.users.subscribe((operation, keys) => { console.log(`Collection changed: ${operation}`, keys); }); // Later, to unsubscribe unsubscribe(); ``` -------------------------------- ### Query Stages API Source: https://ramifyjs.haroonwaves.com/docs/api/query Details the available stages for building type-safe queries. ```APIDOC ## Query Stages The query API uses a type-safe fluent interface with different stages: ### `WhereStage` Available after `where(field)`. Provides filtering operators: * `equals(value)` * `anyOf(values)` * `allOf(values)` ### `ExecutableStage` Available after applying a filter or using `where(criteria)`. Provides: * Modifiers: `sortBy()`, `limit()`, `offset()`, `filter()` * Execution: `toArray()`, `first()`, `last()`, `count()`, `delete()`, `modify()` ### `OrderableStage` Available after `sortBy()`. Extends `ExecutableStage` with: * `reverse()` ### `LimitedStage` Available after `limit()` or `offset()`. Extends `ExecutableStage`. ``` -------------------------------- ### Perform CRUD Operations in Ramify DB Source: https://ramifyjs.haroonwaves.com/docs/guides/crud This snippet demonstrates the basic Create, Read, Update, and Delete operations available in Ramify DB. It covers single and bulk operations, as well as query-based modifications and deletions. Use `clear()` to remove all records from a collection. ```javascript // CREATE db.users.add({ id: '1', name: 'John Doe', email: 'john@example.com', ... }); db.users.bulkAdd([user1, user2]); // READ const user = db.users.get('1'); const allUsers = db.users.toArray(); const activeUsers = db.users.where({ status: 'active' }).toArray(); // UPDATE db.users.update('1', { age: 31 }); db.users.bulkUpdate(['1', '2'], { age: 32 }); db.users.where({ status: 'inactive' }).modify({ status: 'active' }); // DELETE db.users.delete('1'); db.users.bulkDelete(['1', '2']); db.users.where({ status: 'inactive' }).delete(); // Clear all db.users.clear(); ``` -------------------------------- ### Tokenized Search Queries Source: https://ramifyjs.haroonwaves.com/docs/guides/search Perform searches on tokenized data using `multiEntry` indexes for exact, any-of, or all-of token matches. This enables advanced search capabilities. ```javascript // Find products has the word only "phone" (exact token match) const phones = db.products.where('_searchTerms').equals(['phone']).toArray(); // Find products containing the word "phone" or "tablet" (any token match) const phonesOrTablets = db.products.where('_searchTerms').anyOf(['phone', 'tablet']).toArray(); // Find products containing the word "phone" and "smart" (all token match) const smartPhones = db.products.where('_searchTerms').allOf(['phone', 'smart']).toArray(); ``` -------------------------------- ### Simple Filter for Small Datasets Source: https://ramifyjs.haroonwaves.com/docs/guides/search Use native JavaScript string methods for filtering collections under ~10,000 records. This approach is efficient for substring matching. ```javascript const searchQuery = 'john'; const results = db.users .filter((user) => user.name.toLowerCase().includes(searchQuery.toLowerCase())); .toArray() ``` -------------------------------- ### Build Simple Equality Query Source: https://ramifyjs.haroonwaves.com/docs/core/queries Use `.where('field').equals('value')` to filter documents based on an exact field match. Ensure the field is indexed for performance. ```javascript // Simple equality const highPriorityMessages = db.messages.where('metadata.priority').equals('high').toArray(); ``` -------------------------------- ### Filtering Methods Source: https://ramifyjs.haroonwaves.com/docs/api/query Apply various filtering conditions after initiating a query with `.where(field)`. ```APIDOC ## Filtering Methods ### `equals(value)` Exact match for the specified field. **Parameters:** - **`value`** (T[K]) - The value to match **Returns:** `ExecutableStage` - An executable query stage ### `anyOf(values)` Match any value in the provided array. **Parameters:** - **`values`** (Array) - Match documents where the field equals any of these values **Returns:** `ExecutableStage` - An executable query stage ### `allOf(values)` Match all values in the provided array (for multi-entry indexes). **Parameters:** - **`values`** (Array) - Match documents where the field contains all of these values **Returns:** `ExecutableStage` - An executable query stage **Note:** This is primarily useful for multi-entry indexed array fields. **Example:** ```javascript // Exact match db.users.where('status').equals('active').toArray(); // Match any of the provided values db.users.where('status').anyOf(['inactive', 'banned']).toArray(); // Match all provided values (for multi-entry indexes) db.users.where('roles').allOf(['admin', 'moderator']).toArray(); ``` ``` -------------------------------- ### Add or update multiple documents in a collection Source: https://ramifyjs.haroonwaves.com/docs/api/collection Use `bulkPut()` to efficiently insert or update multiple documents. It overwrites existing documents if their primary keys match. This method batches notifications. ```javascript const userIds = db.users.bulkPut([ { id: '1', name: 'Alice Updated' }, { id: '2', name: 'Bob Updated' }, ]); ``` -------------------------------- ### React Live Query Hook Source: https://ramifyjs.haroonwaves.com/docs/getting-started Use the `useLiveQuery` hook from `@ramifyjs/react-hooks` to fetch and subscribe to live query results in React components. The component automatically re-renders when the specified collections change. ```javascript import { useLiveQuery } from '@ramifyjs/react-hooks'; function UserList() { const users = useLiveQuery( () => db.users .where({ status: 'active' }) .sortBy('name') .reverse() .limit(10) .toArray(), { collections: [db.users], others: [] } ); return (
    {users?.map(user => (
  • {user.name} - {user.age}
  • ))}
); } ``` -------------------------------- ### Add a document to a collection Source: https://ramifyjs.haroonwaves.com/docs/api/collection Use `add()` to insert a single document. It throws an error if a document with the same primary key already exists. Use `put()` for upsert behavior. ```javascript // Throws if ID '1' exists const userId = db.users.add({ id: '1', name: 'Alice', email: 'alice@example.com', ... }); ``` -------------------------------- ### Iterate over all documents in a collection Source: https://ramifyjs.haroonwaves.com/docs/api/collection Use `each(callback)` to iterate through every document in the collection. A callback function is executed for each document, receiving the document as an argument. ```javascript db.users.each((user) => { console.log(user.name); }); ``` -------------------------------- ### Sort Data Ascending and Descending Source: https://ramifyjs.haroonwaves.com/docs/guides/pagination-sorting Use `sortBy()` for ascending order and chain `reverse()` for descending order. Sorting is not optimized by indexes but filtering with `where()` improves performance before sorting. ```javascript // Sort by any field (ascending) const sorted = db.users.sortBy('age').toArray(); ``` ```javascript // Sort in descending order const reversed = db.users.sortBy('age').reverse().toArray(); ``` ```javascript // Combine with where queries const managers = db.users.where('roles').anyOf(['manager']).sortBy('name').toArray(); ``` -------------------------------- ### Sync Multiple Collections Independently Source: https://ramifyjs.haroonwaves.com/docs/guides/persistence Subscribe to changes in different collections (e.g., 'users' and 'posts') independently to manage their synchronization with external storage separately. ```typescript // Users sync db.users.subscribe(async (type, keys) => { /* sync logic */ }); // Posts sync db.posts.subscribe(async (type, keys) => { /* sync logic */ }); ``` -------------------------------- ### Add or update a document in a collection Source: https://ramifyjs.haroonwaves.com/docs/api/collection Use `put()` to insert a new document or overwrite an existing one if a document with the same primary key is found. ```javascript // Overwrites if ID '1' exists const userId = db.users.put({ id: '1', name: 'Alice Updated', email: 'alice@example.com', ... }); ``` -------------------------------- ### Add multiple documents to a collection Source: https://ramifyjs.haroonwaves.com/docs/api/collection Use `bulkAdd()` for efficient insertion of multiple documents. It throws an error if any document's primary key already exists. This method batches notifications for performance. ```javascript const userIds = db.users.bulkAdd([ { id: '1', name: 'Alice' }, { id: '2', name: 'Bob' }, ]); ``` -------------------------------- ### Subscriptions Source: https://ramifyjs.haroonwaves.com/docs/api/collection Methods for subscribing to and unsubscribing from collection changes. ```APIDOC ## subscribe(callback) ### Description Subscribes to changes in the collection. The callback is invoked whenever documents are added, updated, deleted, or the collection is cleared. ### Method N/A (Method call on collection object) ### Endpoint N/A ### Parameters #### Path Parameters - **cb** (Observer) - Required - Callback function invoked on collection changes. `Observer` is defined as `(type: CollectionOperation, keys: Pk[]) => void | Promise`, where `CollectionOperation` can be 'create', 'update', 'delete', or 'clear'. ### Request Example ```javascript const unsubscribe = db.users.subscribe((operation, keys) => { console.log(`Collection changed: ${operation}`, keys); }); // Later, to unsubscribe unsubscribe(); ``` ### Response #### Success Response (() => void) - **unsubscribeFn** (() => void) - An unsubscribe function to stop listening to changes. ### Response Example (Returns a function, not a direct value) --- ## unsubscribe(callback) ### Description Unsubscribes a previously registered callback from collection changes. ### Method N/A (Method call on collection object) ### Endpoint N/A ### Parameters #### Path Parameters - **cb** (Observer) - Required - The callback function to unsubscribe. ### Request Example ```javascript const callback = (operation, keys) => { console.log('Changed:', operation, keys); }; db.users.subscribe(callback); // Later db.users.unsubscribe(callback); ``` ### Response #### Success Response (void) - This method does not return a value. ### Response Example N/A ``` -------------------------------- ### Update multiple documents with specific changes Source: https://ramifyjs.haroonwaves.com/docs/api/collection Use `bulkUpdate()` to apply a set of changes to multiple documents identified by their primary keys. Returns an array of primary keys for updated documents, or `undefined` for documents not found. ```javascript const updated = db.users.bulkUpdate(['1', '2', '3'], { status: 'inactive' }); ``` -------------------------------- ### Skip Results with Offset Source: https://ramifyjs.haroonwaves.com/docs/api/query Skip the first N matching documents before returning results. Typically used in conjunction with `.limit()` for pagination. ```javascript db.users.where('status').equals('active').limit(10).offset(10).toArray(); ``` -------------------------------- ### Collection Data Operations Source: https://ramifyjs.haroonwaves.com/docs/api/collection Methods for retrieving counts, primary keys, checking existence, and iterating over documents in a collection. ```APIDOC ## count() ### Description Returns the number of documents in the collection. ### Method N/A (Method call on collection object) ### Endpoint N/A ### Parameters None ### Request Example ```javascript const totalUsers = db.users.count(); ``` ### Response #### Success Response (number) - **count** (number) - The total number of documents in the collection. ### Response Example ```json 150 ``` --- ## keys() ### Description Returns all primary keys in the collection. ### Method N/A (Method call on collection object) ### Endpoint N/A ### Parameters None ### Request Example ```javascript const userIds = db.users.keys(); ``` ### Response #### Success Response (Array) - **keys** (Array) - An array containing all primary keys. ### Response Example ```json ["1", "2", "3"] ``` --- ## has(key) ### Description Checks if a document with the given primary key exists. ### Method N/A (Method call on collection object) ### Endpoint N/A ### Parameters #### Path Parameters - **key** (T[Pk]) - Required - The primary key to check. ### Request Example ```javascript if (db.users.has('1')) { console.log('User exists'); } ``` ### Response #### Success Response (boolean) - **exists** (boolean) - `true` if the document exists, `false` otherwise. ### Response Example ```json true ``` --- ## each(callback) ### Description Iterates over all documents in the collection, executing a callback for each. ### Method N/A (Method call on collection object) ### Endpoint N/A ### Parameters #### Path Parameters - **callback** ((document: T) => void) - Required - Function to execute for each document. ### Request Example ```javascript db.users.each((user) => { console.log(user.name); }); ``` ### Response #### Success Response (void) - This method does not return a value. ### Response Example N/A ``` -------------------------------- ### Skip a number of results in a query Source: https://ramifyjs.haroonwaves.com/docs/api/collection Use `offset(n)` to skip a specified number of documents before returning results. This is often used in conjunction with `limit()` for pagination. ```javascript db.users.limit(10).offset(5).toArray(); ``` -------------------------------- ### Limit Number of Results Source: https://ramifyjs.haroonwaves.com/docs/api/query Restrict the query to return only the first N matching documents. ```javascript db.users.where('status').equals('active').limit(10).toArray(); ``` -------------------------------- ### Sort Query Results by Field Source: https://ramifyjs.haroonwaves.com/docs/api/query Sort the query results in ascending order based on the specified field. This stage must be followed by `.reverse()` to sort in descending order. ```javascript db.users.where('status').equals('active').sortBy('name').toArray(); ```