Skip to content

Cloudflare D1

This guide provides specific information about using workers-qb with Cloudflare D1, Cloudflare's serverless SQL database.

Cloudflare D1 Database

Cloudflare D1 is a globally distributed SQL database designed for serverless environments. It's directly integrated with Cloudflare Workers, providing low-latency access to data from the edge. workers-qb is particularly well-suited for working with D1 due to its lightweight nature and focus on performance in edge contexts.

D1QB Class

To interact with Cloudflare D1 databases using workers-qb, you will use the D1QB class. This class extends the base QueryBuilder and is specifically tailored for D1's API.

Connecting to D1

To connect to your D1 database, you need to obtain a D1 database binding from your Cloudflare Worker environment. This binding is then passed to the D1QB constructor.

Example: Connecting to D1 in a Cloudflare Worker

import { D1QB } from 'workers-qb';

export interface Env {
  DB: D1Database; // 'DB' is the name of your D1 database binding in wrangler.toml
}

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const qb = new D1QB(env.DB); // Initialize D1QB with the D1 binding

    // ... your queries using qb ...

    return new Response("D1 queries executed");
  },
};

Make sure you have configured your D1 database binding correctly in your wrangler.toml file. For example:

# wrangler.toml
name = "my-worker-app"
main = "src/index.ts"
compatibility_date = "2023-08-01"

[[d1_databases]]
binding = "DB" # This 'DB' binding name should match the 'Env' interface
database_name = "my-database"
database_id = "your-database-uuid"

D1 Specific Examples

Here are examples demonstrating common operations using D1QB.

Basic Queries with D1QB

All basic and advanced query operations described in the Basic Queries and Advanced Queries sections are fully applicable to D1QB. You can use createTable, dropTable, insert, select, update, delete, joins, modular select builder, where clauses, etc., just as demonstrated in those sections, replacing PGQB or DOQB with D1QB.

Example: Inserting and Fetching Data in D1

import { D1QB } from 'workers-qb';

export interface Env {
  DB: D1Database;
}

type Product = {
  id: number;
  name: string;
  price: number;
};

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const qb = new D1QB(env.DB);

    // Create table (if not exists) - you'd typically do this in migrations
    await qb.createTable({
        tableName: 'products',
        ifNotExists: true,
        schema: `
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            price REAL NOT NULL
        `
    }).execute();

    // Insert a product
    const insertedProduct = await qb.insert<Product>({
      tableName: 'products',
      data: {
        name: 'Example Product',
        price: 19.99,
      },
      returning: ['id', 'name', 'price'],
    }).execute();

    console.log('Inserted product:', insertedProduct.results);

    // Fetch all products
    const allProducts = await qb.fetchAll<Product>({
      tableName: 'products',
    }).execute();

    console.log('All products:', allProducts.results);

    return Response.json({
      insertedProduct: insertedProduct.results,
      allProducts: allProducts.results,
    });
  },
};

Batch Operations in D1

D1 supports batch operations, which can significantly improve performance when executing multiple queries at once. workers-qb provides the batchExecute method on D1QB to leverage this feature.

Example: Batch Inserting Multiple Products

import { D1QB } from 'workers-qb';

export interface Env {
  DB: D1Database;
}

type Product = {
  id: number;
  name: string;
  price: number;
};

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const qb = new D1QB(env.DB);

    const productsToInsert = [
      { name: 'Product A', price: 9.99 },
      { name: 'Product B', price: 24.50 },
      { name: 'Product C', price: 15.75 },
    ];

    const insertQueries = productsToInsert.map(productData =>
      qb.insert<Product>({
        tableName: 'products',
        data: productData,
        returning: ['id', 'name', 'price'],
      }).getQueryAll() // Get the Query object for batchExecute
    );

    const batchResults = await qb.batchExecute(insertQueries);

    const insertedProducts = batchResults.map(result => result.results);

    console.log('Batch inserted products:', insertedProducts);

    return Response.json({
      batchInsertedProducts: insertedProducts,
    });
  },
};

In this example, we create an array of Query objects using getQueryAll() from individual insert operations and then execute them all in a single batch using qb.batchExecute(). This is more efficient than executing each insert query separately.

Note: Batch operations in D1 have limitations. Refer to the Cloudflare D1 documentation for details on batch operation constraints.

This guide provides an overview of using workers-qb with Cloudflare D1. Explore other sections of the documentation for more general query building concepts and advanced features that are applicable to D1 as well. Next, see the guide for Cloudflare Durable Objects.