Real-time Subscriptions in Drift KV

Drift KV provides a powerful real-time subscription system through the DriftWatcher class, allowing you to monitor and react to changes in your data in real-time.

Basic Usage

Watching a Single Entity

import { Drift, DriftEntity } from "drift-kv";

const UserEntity = new DriftEntity({
  name: "user",
  options: {
    timestamps: true,
  },
  schema: (z) => ({
    name: z.string(),
    email: z.string().email(),
    status: z.enum(["online", "offline"]),
  }),
});

const drift = new Drift({
  client: await Deno.openKv(),
  schemas: {
    entities: {
      user: UserEntity,
    },
  },
});

// Watch a specific user
const { cancel } = drift.entities.user.watch(
  {
    where: {
      id: "user-123",
    },
    select: {
      name: true,
      status: true,
    },
  },
  (changes) => {
    console.log("User changed:", changes);
  }
);

Watching Multiple Entities

// Watch all active users
const { cancel } = drift.entities.user.watch(
  {
    where: {
      status: "online",
    },
    select: {
      id: true,
      name: true,
      status: true,
    },
  },
  (users) => {
    console.log("Active users changed:", users);
  }
);

Real-world Examples

Chat Application

const MessageEntity = new DriftEntity({
  name: "message",
  options: {
    timestamps: true,
  },
  schema: (z) => ({
    chatId: z.string().uuid(),
    userId: z.string().uuid(),
    content: z.string(),
  }),
});

// Watch new messages in a specific chat
const { cancel } = drift.entities.message.watch(
  {
    where: {
      chatId: "chat-123",
      createdAt: {
        gte: new Date(),
      },
    },
  },
  (messages) => {
    // Update UI with new messages
    updateChatUI(messages);
  }
);

Real-time Dashboard

const MetricEntity = new DriftEntity({
  name: "metric",
  options: {
    timestamps: true,
  },
  schema: (z) => ({
    name: z.string(),
    value: z.number(),
  }),
});

// Watch system metrics
const { cancel } = drift.entities.metric.watchAll(
  {
    where: {
      timestamp: {
        gte: new Date(Date.now() - 300000), // Last 5 minutes
      },
    },
    select: {
      name: true,
      value: true,
      timestamp: true,
    },
  },
  (metrics) => {
    // Update dashboard metrics
    updateDashboardMetrics(metrics);
  }
);

Error Handling

try {
  const { cancel } = drift.entities.user.watch({
    where: {
      status: "online",
    },
    callback: (users) => {
      console.log("Users updated:", users);
    },
  });

  // Later, unsubscribe to stop watching
  cancel();
} catch (error) {
  if (error instanceof DriftError) {
    console.error("Watcher error:", error.message);
  }
}

Performance Considerations

Optimizing Watchers

  1. Selective Fields
// Good: Select only needed fields
const { cancel } = drift.entities.user.watch({
  select: {
    id: true,
    status: true,
  },
  callback: (users) => {
    console.log("Users updated:", users);
  }
});

// Avoid: Watching all fields
drift.entities.user.watchAll({}, callback);
  1. Efficient Filtering
// Good: Use indexed fields for filtering
const { cancel } = drift.entities.user.watch({
  where: {
    status: "online", // Indexed field
  },
  callback: (users) => {
    console.log("Users updated:", users);
  }
);

Best Practices

  1. Resource Management

    • Always unsubscribe when watchers are no longer needed
    • Limit the number of active watchers
    • Use selective fields to reduce data transfer
  2. Error Handling

    • Implement proper error handling
    • Handle reconnection scenarios
    • Log watcher errors appropriately
  3. Performance

    • Use efficient filters
    • Select only necessary fields
    • Consider batching updates
  4. Type Safety

    • Leverage TypeScript types
    • Validate data with Zod
    • Handle edge cases

Next Steps

Built for Deno KV

Discover Drift KV: The Ultimate Type-Safe ORM for Deno KV

Experience a powerful ORM with real-time subscriptions, job queues, and seamless compatibility across Deno KV, Node.js, Bun.js, and Edge environments.