### Install Dependencies and Run Playground Server Source: https://github.com/dschewchenko/drizzle-uncache/blob/main/playground/README.md These commands are used to set up and launch the Drizzle Uncache playground server. 'bun install' installs project dependencies, and 'bun run playground' starts the server. ```shell bun install bun run playground ``` -------------------------------- ### Setup Redis Cache with Drizzle ORM and Unstorage Source: https://context7.com/dschewchenko/drizzle-uncache/llms.txt Demonstrates how to set up a cache instance using the Redis driver from unstorage and integrate it with Drizzle ORM. This example shows explicit query caching with a default TTL and logging cache hits/misses. ```typescript import { drizzle } from "drizzle-orm/node-postgres"; import { Client } from "pg"; import { pgTable, integer, text } from "drizzle-orm/pg-core"; import { createStorage } from "unstorage"; import redisDriver from "unstorage/drivers/redis"; import { unstorageCache } from "drizzle-uncache"; // Setup storage with Redis driver const storage = createStorage({ driver: redisDriver({ url: "redis://localhost:6379" }) }); // Create cache with 60-second default TTL const cache = unstorageCache({ storage, config: { ex: 60 }, debug: true // Enable cache hit/miss logging }); // Define schema const users = pgTable("users", { id: integer("id").primaryKey().generatedAlwaysAsIdentity(), name: text("name").notNull(), }); // Initialize Drizzle with cache const client = new Client({ connectionString: process.env.DATABASE_URL }); await client.connect(); const db = drizzle(client, { schema: { users }, cache }); // Query with explicit caching (60s TTL) const allUsers = await db .select() .from(users) .$withCache({ config: { ex: 60 } }) .all(); // Second query hits cache const cachedUsers = await db .select() .from(users) .$withCache({ config: { ex: 60 } }) .all(); ``` -------------------------------- ### Start Redis Docker Container Source: https://github.com/dschewchenko/drizzle-uncache/blob/main/playground/README.md This command starts a Redis instance in a Docker container, mapping port 6379 to the host machine. This is a prerequisite for running the Drizzle Uncache playground server. ```shell docker run --rm -p 6379:6379 redis:7-alpine ``` -------------------------------- ### Direct UnstorageCache Instantiation with Filesystem Driver Source: https://context7.com/dschewchenko/drizzle-uncache/llms.txt Illustrates how to directly instantiate the UnstorageCache class for advanced configurations, using the filesystem driver with a custom prefix. This example demonstrates caching with a TTL in milliseconds and preserving existing expiration. ```typescript import { createStorage, prefixStorage } from "unstorage"; import fsLiteDriver from "unstorage/drivers/fs-lite"; import { UnstorageCache } from "drizzle-uncache"; import { drizzle } from "drizzle-orm/better-sqlite3"; import Database from "better-sqlite3"; import { sqliteTable, integer, text } from "drizzle-orm/sqlite-core"; // Create storage with filesystem driver and custom prefix const baseStorage = createStorage({ driver: fsLiteDriver({ base: "./cache" }) }); const storage = prefixStorage(baseStorage, "myapp"); // Instantiate cache directly const cache = new UnstorageCache(storage, { base: "drizzle:v1", config: { px: 30000 }, // 30 seconds in milliseconds global: false, // Only cache queries with explicit $withCache debug: true }); const products = sqliteTable("products", { id: integer("id").primaryKey({ autoIncrement: true }), name: text("name").notNull(), price: integer("price").notNull(), }); const sqlite = new Database("products.db"); const db = drizzle(sqlite, { schema: { products }, cache }); // Cache with keepTtl to preserve existing expiration await db .select() .from(products) .$withCache({ config: { ex: 120, keepTtl: true } }) .all(); ``` -------------------------------- ### Example Usage: Postgres with Redis Cache Source: https://github.com/dschewchenko/drizzle-uncache/blob/main/README.md Demonstrates setting up Drizzle ORM with PostgreSQL and Redis as the cache backend using drizzle-uncache. It shows how to initialize unstorage with a Redis driver and then integrate it with Drizzle. ```typescript import { Client } from "pg" import { drizzle } from "drizzle-orm/node-postgres" import { integer, pgTable, text } from "drizzle-orm/pg-core" import { createStorage } from "unstorage" import redisDriver from "unstorage/drivers/redis" import { unstorageCache } from "drizzle-uncache" const storage = createStorage({ driver: redisDriver({ url: process.env.REDIS_URL }) }) const cache = unstorageCache({ storage, config: { ex: 60 } }) const users = pgTable("users", { id: integer("id").primaryKey().generatedAlwaysAsIdentity(), name: text("name").notNull(), }) const client = new Client({ connectionString: process.env.DATABASE_URL }) await client.connect() const db = drizzle(client, { schema: { users }, cache }) const all = await db .select() .from(users) .$withCache({ config: { ex: 60 } }) .all() ``` -------------------------------- ### Install drizzle-uncache with npm/yarn/pnpm/bun Source: https://github.com/dschewchenko/drizzle-uncache/blob/main/README.md Installs the necessary packages for drizzle-uncache, unstorage, and drizzle-orm. These commands are compatible with npm, yarn, pnpm, and bun package managers. ```sh # bun bun add drizzle-uncache unstorage drizzle-orm # pnpm pnpm add drizzle-uncache unstorage drizzle-orm # npm npm install drizzle-uncache unstorage drizzle-orm # yarn yarn add drizzle-uncache unstorage drizzle-orm ``` -------------------------------- ### GET /keys Source: https://github.com/dschewchenko/drizzle-uncache/blob/main/playground/README.md Lists all cache keys currently stored, including those in Redis. ```APIDOC ## GET /keys ### Description Retrieves a list of all cache keys managed by the system, including those stored in Redis. ### Method GET ### Endpoint /keys ### Parameters #### Path Parameters None #### Query Parameters None ### Request Example None ### Response #### Success Response (200) - **keys** (array) - An array of strings, where each string is a cache key. #### Response Example ```json { "keys": [ "user:1", "user:2" ] } ``` ``` -------------------------------- ### GET /users/create Source: https://github.com/dschewchenko/drizzle-uncache/blob/main/playground/README.md Inserts a new random user into the database. This action also triggers cache invalidation for relevant entries. ```APIDOC ## GET /users/create ### Description Creates a new random user record in the database. This operation is designed to test cache invalidation mechanisms by modifying data that is cached. ### Method GET ### Endpoint /users/create ### Parameters #### Path Parameters None #### Query Parameters None ### Request Example None ### Response #### Success Response (200) - **message** (string) - A confirmation message indicating the user was created. - **userId** (integer) - The ID of the newly created user. #### Response Example ```json { "message": "User created successfully", "userId": 123 } ``` ``` -------------------------------- ### Vercel KV Integration with Drizzle-Uncache Source: https://context7.com/dschewchenko/drizzle-uncache/llms.txt This example demonstrates integrating drizzle-uncache with Vercel KV for serverless environments. It sets up the Vercel KV driver, configures the cache with a base key and expiration, defines a Drizzle schema for articles, and implements API route handlers for fetching and revalidating articles. Dependencies include drizzle-orm, @vercel/postgres, unstorage, and drizzle-uncache. ```typescript import { drizzle } from "drizzle-orm/vercel-postgres"; import { sql as vercelSql } from "@vercel/postgres"; import { pgTable, serial, text, timestamp } from "drizzle-orm/pg-core"; import { createStorage } from "unstorage"; import vercelKVDriver from "unstorage/drivers/vercel-kv"; import { unstorageCache } from "drizzle-uncache"; // Vercel KV driver configuration const storage = createStorage({ driver: vercelKVDriver({ url: process.env.KV_REST_API_URL, token: process.env.KV_REST_API_TOKEN, }), }); const cache = unstorageCache({ storage, base: "prod:cache", config: { ex: 180 }, // 3 minutes default debug: false // Disable in production }); const articles = pgTable("articles", { id: serial("id").primaryKey(), slug: text("slug").notNull().unique(), title: text("title").notNull(), body: text("body").notNull(), publishedAt: timestamp("published_at").defaultNow(), }); const db = drizzle(vercelSql, { schema: { articles }, cache }); // API route handler export async function GET(request: Request) { const { searchParams } = new URL(request.url); const slug = searchParams.get("slug"); if (!slug) { return Response.json({ error: "Missing slug" }, { status: 400 }); } const article = await db .select() .from(articles) .where(eq(articles.slug, slug)) .$withCache({ tag: `article:${slug}`, config: { ex: 3600 } // 1 hour for public articles }) .get(); if (!article) { return Response.json({ error: "Not found" }, { status: 404 }); } return Response.json({ article }); } // Revalidate on webhook export async function POST(request: Request) { const { slug } = await request.json(); await cache.onMutate({ tags: `article:${slug}` }); return Response.json({ revalidated: true }); } ``` -------------------------------- ### GET /health Source: https://github.com/dschewchenko/drizzle-uncache/blob/main/playground/README.md Checks the health of the Redis connection by pinging it. ```APIDOC ## GET /health ### Description Pings the Redis server to verify connectivity. ### Method GET ### Endpoint /health ### Parameters #### Path Parameters None #### Query Parameters None ### Request Example None ### Response #### Success Response (200) - **message** (string) - A confirmation message indicating Redis is reachable. #### Response Example ```json { "message": "Redis is healthy" } ``` ``` -------------------------------- ### GET /users Source: https://github.com/dschewchenko/drizzle-uncache/blob/main/playground/README.md Retrieves a list of users with caching enabled. Data is served from the cache with a 30-second Time-To-Live (TTL). ```APIDOC ## GET /users ### Description Fetches a list of users. This endpoint utilizes Drizzle's `.$withCache()` functionality, meaning the response is served from the cache with a 30-second TTL. ### Method GET ### Endpoint /users ### Parameters #### Path Parameters None #### Query Parameters None ### Request Example None ### Response #### Success Response (200) - **users** (array) - An array of user objects. - **id** (integer) - The user's unique identifier. - **name** (string) - The user's name. - **email** (string) - The user's email address. #### Response Example ```json { "users": [ { "id": 1, "name": "John Doe", "email": "john.doe@example.com" }, { "id": 2, "name": "Jane Smith", "email": "jane.smith@example.com" } ] } ``` ``` -------------------------------- ### GET /clear Source: https://github.com/dschewchenko/drizzle-uncache/blob/main/playground/README.md Clears all entries from the 'users' table and purges associated cache keys from Redis. ```APIDOC ## GET /clear ### Description Clears all records from the users table and invalidates all corresponding cache entries stored in Redis. This is a comprehensive way to reset the cached user data. ### Method GET ### Endpoint /clear ### Parameters #### Path Parameters None #### Query Parameters None ### Request Example None ### Response #### Success Response (200) - **message** (string) - A confirmation message indicating that the users table and cache have been cleared. #### Response Example ```json { "message": "Users table and cache cleared successfully" } ``` ``` -------------------------------- ### Multi-Table Query Caching with Automatic Invalidation in TypeScript Source: https://context7.com/dschewchenko/drizzle-uncache/llms.txt This example demonstrates caching complex queries involving multiple tables using Drizzle Uncache and Redis. The cache is automatically invalidated when any of the involved tables (categories, products, reviews) are modified. It requires `drizzle-orm`, `unstorage`, and a Redis instance. ```typescript import { drizzle } from "drizzle-orm/node-postgres"; import { Client } from "pg"; import { pgTable, serial, text, integer, timestamp } from "drizzle-orm/pg-core"; import { eq } from "drizzle-orm"; import { createStorage } from "unstorage"; import redisDriver from "unstorage/drivers/redis"; import { unstorageCache } from "drizzle-uncache"; const storage = createStorage({ driver: redisDriver({ url: process.env.REDIS_URL }) }); const cache = unstorageCache({ storage, config: { ex: 300 } }); const categories = pgTable("categories", { id: serial("id").primaryKey(), name: text("name").notNull(), }); const products = pgTable("products", { id: serial("id").primaryKey(), categoryId: integer("category_id").references(() => categories.id), name: text("name").notNull(), price: integer("price").notNull(), }); const reviews = pgTable("reviews", { id: serial("id").primaryKey(), productId: integer("product_id").references(() => products.id), rating: integer("rating").notNull(), comment: text("comment"), }); const client = new Client({ connectionString: process.env.DATABASE_URL }); await client.connect(); const db = drizzle(client, { schema: { categories, products, reviews }, cache }); // Complex join query cached across multiple tables const productWithReviews = await db .select({ productId: products.id, productName: products.name, categoryName: categories.name, reviewRating: reviews.rating, reviewComment: reviews.comment, }) .from(products) .leftJoin(categories, eq(products.categoryId, categories.id)) .leftJoin(reviews, eq(reviews.productId, products.id)) .where(eq(products.id, 100)) .$withCache({ config: { ex: 600 } }) .all(); // Mutation to ANY of these tables invalidates the cached query await db.insert(reviews).values({ productId: 100, rating: 5, comment: "Excellent!" }); // Cache automatically invalidated, next query hits database const refreshedData = await db .select({ productId: products.id, productName: products.name, categoryName: categories.name, reviewRating: reviews.rating, reviewComment: reviews.comment, }) .from(products) .leftJoin(categories, eq(products.categoryId, categories.id)) .leftJoin(reviews, eq(reviews.productId, products.id)) .where(eq(products.id, 100)) .$withCache({ config: { ex: 600 } }) .all(); // Fresh data from database ``` -------------------------------- ### Preserving Cache TTL with keepTtl Option in TypeScript Source: https://context7.com/dschewchenko/drizzle-uncache/llms.txt This example demonstrates how to use the `keepTtl` option in Drizzle Uncache to preserve the original Time-To-Live (TTL) of a cache entry when updating its value. This is useful for maintaining consistent cache expiration periods across updates. It requires `drizzle-orm`, `unstorage`, and a Redis instance. ```typescript import { drizzle } from "drizzle-orm/node-postgres"; import { Client } from "pg"; import { pgTable, serial, integer, timestamp } from "drizzle-orm/pg-core"; import { createStorage } from "unstorage"; import redisDriver from "unstorage/drivers/redis"; import { unstorageCache } from "drizzle-uncache"; const storage = createStorage({ driver: redisDriver({ url: process.env.REDIS_URL }) }); const cache = unstorageCache({ storage, config: { ex: 3600 } }); // 1 hour default const pageViews = pgTable("page_views", { id: serial("id").primaryKey(), url: text("url").notNull(), count: integer("count").notNull().default(0), lastViewed: timestamp("last_viewed").defaultNow(), }); const client = new Client({ connectionString: process.env.DATABASE_URL }); await client.connect(); const db = drizzle(client, { schema: { pageViews }, cache }); // Initial cache with 1-hour TTL const initialViews = await db .select() .from(pageViews) .$withCache({ config: { ex: 3600 } }) .all(); // Later update: increment counter and update cache // keepTtl preserves the original 1-hour expiration await db .update(pageViews) .set({ count: sql`${pageViews.count} + 1` }) .execute(); const updatedViews = await db .select() .from(pageViews) .$withCache({ config: { ex: 60, // Would normally set 60s TTL keepTtl: true // But keepTtl preserves original 3600s TTL } }) .all(); // Cache still expires at original time, not 60 seconds from now ``` -------------------------------- ### Cache Configuration Options: TTL, Prefix, Global Caching Source: https://context7.com/dschewchenko/drizzle-uncache/llms.txt Explores various cache configuration options, including setting a default TTL, defining a key prefix, enabling global caching for all queries, and demonstrating different TTL formats (seconds, milliseconds, absolute timestamps). ```typescript import { unstorageCache } from "drizzle-uncache"; import { createStorage } from "unstorage"; import lruCacheDriver from "unstorage/drivers/lru-cache"; // LRU cache for development const storage = createStorage({ driver: lruCacheDriver({ max: 500 }) }); const cache = unstorageCache({ storage, base: "api:cache", // Key prefix: "api:cache:drizzle:cache:..." config: { ex: 300 // Default: 300 seconds (5 minutes) }, global: true, // Cache ALL queries automatically debug: process.env.NODE_ENV === "development" }); // Alternative TTL configurations const cacheWithPx = unstorageCache({ storage, config: { px: 5000 } // TTL in milliseconds }); const cacheWithExat = unstorageCache({ storage, config: { exat: Math.floor(Date.now() / 1000) + 3600 // Absolute Unix timestamp (seconds) } }); const cacheWithPxat = unstorageCache({ storage, config: { pxat: Date.now() + 3600000 // Absolute Unix timestamp (milliseconds) } }); ``` -------------------------------- ### Cache Configuration Options Source: https://context7.com/dschewchenko/drizzle-uncache/llms.txt Details on configuring TTL, key prefixes, and caching behavior with various options available in drizzle-uncache. ```APIDOC ## Cache Configuration Options ### Description Configure TTL, key prefixes, and caching behavior with flexible options. ### Method Factory function/Class instantiation parameters ### Endpoint N/A ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```typescript import { unstorageCache } from "drizzle-uncache"; import { createStorage } from "unstorage"; import lruCacheDriver from "unstorage/drivers/lru-cache"; // LRU cache for development const storage = createStorage({ driver: lruCacheDriver({ max: 500 }) }); const cache = unstorageCache({ storage, base: "api:cache", // Key prefix: "api:cache:drizzle:cache:..." config: { ex: 300 // Default: 300 seconds (5 minutes) }, global: true, // Cache ALL queries automatically debug: process.env.NODE_ENV === "development" }); // Alternative TTL configurations const cacheWithPx = unstorageCache({ storage, config: { px: 5000 } // TTL in milliseconds }); const cacheWithExat = unstorageCache({ storage, config: { exat: Math.floor(Date.now() / 1000) + 3600 // Absolute Unix timestamp (seconds) } }); const cacheWithPxat = unstorageCache({ storage, config: { pxat: Date.now() + 3600000 // Absolute Unix timestamp (milliseconds) } }); ``` ### Response N/A (This section describes configuration options, not an API response) ### Response Example N/A ``` -------------------------------- ### In-Memory Driver for Testing with Drizzle-Uncache Source: https://context7.com/dschewchenko/drizzle-uncache/llms.txt This snippet shows how to use the memory driver from unstorage with drizzle-uncache for testing purposes. It sets up an in-memory cache and a Drizzle database, then demonstrates caching user queries and invalidating the cache on mutations. Dependencies include vitest, unstorage, drizzle-orm, and better-sqlite3. ```typescript import { describe, it, expect, beforeEach } from "vitest"; import { createStorage } from "unstorage"; import memoryDriver from "unstorage/drivers/memory"; import { unstorageCache } from "drizzle-uncache"; import { drizzle } from "drizzle-orm/better-sqlite3"; import Database from "better-sqlite3"; import { sqliteTable, integer, text } from "drizzle-orm/sqlite-core"; describe("User service", () => { let cache; let db; beforeEach(() => { // Fresh in-memory cache for each test const storage = createStorage({ driver: memoryDriver() }); cache = unstorageCache({ storage, config: { ex: 60 } }); const sqlite = new Database(":memory:"); const users = sqliteTable("users", { id: integer("id").primaryKey({ autoIncrement: true }), name: text("name").notNull(), }); sqlite.exec(`CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL)`) db = drizzle(sqlite, { schema: { users }, cache }); }); it("caches user queries", async () => { const users = db.schema.users; await db.insert(users).values({ name: "Alice" }); const first = await db .select() .from(users) .$withCache({ config: { ex: 60 } }) .all(); expect(first).toHaveLength(1); // Second call hits cache const second = await db .select() .from(users) .$withCache({ config: { ex: 60 } }) .all(); expect(second).toEqual(first); }); it("invalidates on mutation", async () => { const users = db.schema.users; await db.insert(users).values({ name: "Bob" }); await db .select() .from(users) .$withCache({ config: { ex: 60 } }) .all(); // Mutation invalidates cache await db.insert(users).values({ name: "Charlie" }); const result = await db .select() .from(users) .$withCache({ config: { ex: 60 } }) .all(); expect(result).toHaveLength(2); }); }); ``` -------------------------------- ### UnstorageCache Class Source: https://context7.com/dschewchenko/drizzle-uncache/llms.txt Direct instantiation of the UnstorageCache class for advanced use cases and custom storage configurations. ```APIDOC ## UnstorageCache Class ### Description Direct instantiation for advanced use cases requiring custom storage configurations. ### Method Class instantiation ### Endpoint N/A ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```typescript import { createStorage, prefixStorage } from "unstorage"; import fsLiteDriver from "unstorage/drivers/fs-lite"; import { UnstorageCache } from "drizzle-uncache"; import { drizzle } from "drizzle-orm/better-sqlite3"; import Database from "better-sqlite3"; import { sqliteTable, integer, text } from "drizzle-orm/sqlite-core"; // Create storage with filesystem driver and custom prefix const baseStorage = createStorage({ driver: fsLiteDriver({ base: "./cache" }) }); const storage = prefixStorage(baseStorage, "myapp"); // Instantiate cache directly const cache = new UnstorageCache(storage, { base: "drizzle:v1", config: { px: 30000 }, // 30 seconds in milliseconds global: false, // Only cache queries with explicit $withCache debug: true }); const products = sqliteTable("products", { id: integer("id").primaryKey({ autoIncrement: true }), name: text("name").notNull(), price: integer("price").notNull(), }); const sqlite = new Database("products.db"); const db = drizzle(sqlite, { schema: { products }, cache }); // Cache with keepTtl to preserve existing expiration await db .select() .from(products) .$withCache({ config: { ex: 120, keepTtl: true } }) .all(); ``` ### Response N/A (This is a class instantiation, not an API endpoint) ### Response Example N/A ``` -------------------------------- ### Table-Based Auto-Invalidation with Drizzle and Redis Source: https://context7.com/dschewchenko/drizzle-uncache/llms.txt This snippet demonstrates how to set up table-based auto-invalidation for Drizzle ORM queries using unstorage with a Redis driver. It shows how to configure the cache, define a table, perform cached queries, and how inserting new data automatically invalidates the cache for the 'posts' table. Manual invalidation is also shown. ```typescript import { drizzle } from "drizzle-orm/node-postgres"; import { pgTable, serial, text, timestamp } from "drizzle-orm/pg-core"; import { createStorage } from "unstorage"; import redisDriver from "unstorage/drivers/redis"; import { unstorageCache } from "drizzle-uncache"; import { Client } from "pg"; const storage = createStorage({ driver: redisDriver({ url: process.env.REDIS_URL }) }); const cache = unstorageCache({ storage, config: { ex: 300 } }); const posts = pgTable("posts", { id: serial("id").primaryKey(), title: text("title").notNull(), content: text("content").notNull(), createdAt: timestamp("created_at").defaultNow(), }); const client = new Client({ connectionString: process.env.DATABASE_URL }); await client.connect(); const db = drizzle(client, { schema: { posts }, cache }); // Cache query for 5 minutes const allPosts = await db .select() .from(posts) .$withCache({ config: { ex: 300 } }) .all(); // Insert new post - automatically invalidates posts table cache await db.insert(posts).values({ title: "New Post", content: "Content here" }); // Next query re-fetches from database const updatedPosts = await db .select() .from(posts) .$withCache({ config: { ex: 300 } }) .all(); // Cache MISS, database query executed // Manual invalidation also supported await cache.onMutate({ tables: ["posts"] }); // Or invalidate by Table object await cache.onMutate({ tables: posts }); ``` -------------------------------- ### unstorageCache Factory Function Source: https://context7.com/dschewchenko/drizzle-uncache/llms.txt Factory function to create a new cache instance for Drizzle ORM using unstorage drivers. Supports Redis, filesystem, memory, and more. ```APIDOC ## unstorageCache Factory Function ### Description Factory function that creates a new cache instance for Drizzle ORM. ### Method Factory function (not an HTTP method) ### Endpoint N/A ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```typescript import { drizzle } from "drizzle-orm/node-postgres"; import { Client } from "pg"; import { pgTable, integer, text } from "drizzle-orm/pg-core"; import { createStorage } from "unstorage"; import redisDriver from "unstorage/drivers/redis"; import { unstorageCache } from "drizzle-uncache"; // Setup storage with Redis driver const storage = createStorage({ driver: redisDriver({ url: "redis://localhost:6379" }) }); // Create cache with 60-second default TTL const cache = unstorageCache({ storage, config: { ex: 60 }, debug: true // Enable cache hit/miss logging }); // Define schema const users = pgTable("users", { id: integer("id").primaryKey().generatedAlwaysAsIdentity(), name: text("name").notNull(), }); // Initialize Drizzle with cache const client = new Client({ connectionString: process.env.DATABASE_URL }); await client.connect(); const db = drizzle(client, { schema: { users }, cache }); // Query with explicit caching (60s TTL) const allUsers = await db .select() .from(users) .$withCache({ config: { ex: 60 } }) .all(); // Second query hits cache const cachedUsers = await db .select() .from(users) .$withCache({ config: { ex: 60 } }) .all(); ``` ### Response N/A (This is a factory function, not an API endpoint) ### Response Example N/A ``` -------------------------------- ### Custom Tag-Based Caching with Drizzle and Upstash Redis Source: https://context7.com/dschewchenko/drizzle-uncache/llms.txt This snippet illustrates custom tag-based caching for Drizzle ORM queries using unstorage with the Upstash Redis driver. It shows how to define multiple tables (users, orders), cache queries with specific tags, and invalidate caches across different queries by referencing those tags. It also covers invalidating multiple tags simultaneously. ```typescript import { drizzle } from "drizzle-orm/postgres-js"; import postgres from "postgres"; import { pgTable, serial, text, integer } from "drizzle-orm/pg-core"; import { eq } from "drizzle-orm"; import { createStorage } from "unstorage"; import upstashRedisDriver from "unstorage/drivers/upstash"; import { unstorageCache } from "drizzle-uncache"; const queryClient = postgres(process.env.DATABASE_URL); const storage = createStorage({ driver: upstashRedisDriver({ url: process.env.UPSTASH_REDIS_REST_URL, token: process.env.UPSTASH_REDIS_REST_TOKEN, }), }); const cache = unstorageCache({ storage, config: { ex: 600 } }); const users = pgTable("users", { id: serial("id").primaryKey(), name: text("name").notNull(), email: text("email").notNull().unique(), }); const orders = pgTable("orders", { id: serial("id").primaryKey(), userId: integer("user_id").references(() => users.id), total: integer("total").notNull(), }); const db = drizzle(queryClient, { schema: { users, orders }, cache }); // Cache with custom tag const userWithOrders = await db .select() .from(users) .where(eq(users.id, 42)) .$withCache({ tag: "user:42:profile", config: { ex: 1800 } // 30 minutes }) .all(); // Different query, same tag const userOrders = await db .select() .from(orders) .where(eq(orders.userId, 42)) .$withCache({ tag: "user:42:profile", config: { ex: 1800 } }) .all(); // Invalidate all queries with this tag await cache.onMutate({ tags: "user:42:profile" }); // Multiple tags await cache.onMutate({ tags: ["user:42:profile", "user:43:profile"] }); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.