Skip to content

[Feature]: @kalamdb/react – LiveQuery & LiveQueries (Real-time React SDK)Β #238

@jamals86

Description

@jamals86

πŸš€ Feature Request: @kalamdb/react – LiveQuery & LiveQueries (Real-time React SDK)

Summary

Introduce a new official React package:

@kalamdb/react

This package provides a declarative, minimal, SQL-driven UI layer for KalamDB, enabling developers to build fully real-time applications directly from queries with zero manual subscription management.


🎯 Goals

  • Make KalamDB feel like React + SQL = UI
  • Eliminate boilerplate (fetch + subscribe + state merge)
  • Provide type-safe integration with Drizzle ORM
  • Support both Drizzle ORM and raw SQL modes
  • Support single and multiple live queries
  • Cover full CRUD with built-in mutation state (loading/inserting/updating/deleting)

πŸ“¦ Package: @kalamdb/react

Core primitives

<LiveQuery />
<LiveQueries />

🧠 Core Concepts

1. LiveQuery (single query)

Supports 2 modes:


βœ… Mode 1: Drizzle ORM (type-safe)

<LiveQuery
  table={messageTable}
  where={(m) => eq(m.conversationId, 1)}
  orderBy={(m) => asc(m.createdAt)}
>
  {({ rows, state, insert, update, remove }) => (
    <UI />
  )}
</LiveQuery>

βœ… Mode 2: Raw SQL (full flexibility)

// Using a full SQL query with real-time
<LiveQuery query="SELECT * FROM chat.messages WHERE conversation_id = 1 ORDER BY created_at ASC">
  {({ rows, state, insert }) => (
    <Chat>
      {rows.map((m) => (
        <Chat.Message key={m.id} role={m.role_id}>
          {m.content}
        </Chat.Message>
      ))}

      <Chat.Input
        placeholder="Write a message..."
        onSend={(text) =>
          insert("chat.messages", {
            conversation_id: 1,
            role_id: "user",
            content: text,
          })
        }
      />
    </Chat>
  )}
</LiveQuery>

πŸ‘‰ This mode leverages KalamDB SQL-first design and SUBSCRIBE TO under the hood.


2. LiveQueries (multiple queries)

Supports multiple live queries in one component (Drizzle mode first).


✨ Example: Chat with Typing Indicator (2 tables)

<LiveQueries
  queries={{
    messages: {
      table: messageTable,
      where: (m) => eq(m.conversationId, 1),
      orderBy: (m) => asc(m.createdAt),
    },

    typing: {
      table: typingTable,
      where: (t) => eq(t.conversationId, 1),
    },
  }}
>
  {({ messages, typing, state, insert }) => (
    <Chat>
      {state.loading && <Chat.Status>Loading chat...</Chat.Status>}

      {messages.rows.map((m) => (
        <Chat.Message key={m.id} role={m.roleId}>
          {m.content}
        </Chat.Message>
      ))}

      {typing.rows.length > 0 && (
        <Chat.Typing>
          {typing.rows.map((t) => t.userName).join(", ")} typing...
        </Chat.Typing>
      )}

      <Chat.Input
        disabled={messages.state.inserting}
        onTyping={() =>
          insert(typingTable).values({
            conversationId: 1,
            userId: "user_123",
            userName: "Jamal",
            eventType: "typing",
          })
        }
        onSend={(text) =>
          insert(messageTable).values({
            conversationId: 1,
            roleId: "user",
            content: text,
          })
        }
      />
    </Chat>
  )}
</LiveQueries>

βš™οΈ API Design

LiveQuery

<LiveQuery
  // Mode 1 (Drizzle)
  table={Table}
  where={(t) => ...}
  orderBy={(t) => ...}

  // OR Mode 2 (SQL)
  query="SELECT ..."
>
  {(ctx) => ...}
</LiveQuery>

LiveQueries

<LiveQueries
  queries={{
    key: {
      table,
      where,
      orderBy,
    }
  }}
>
  {(ctx) => ...}
</LiveQueries>

🧩 Render Context Shape

Single query

{
  rows: T[],
  state: {
    loading: boolean,
    inserting: boolean,
    updating: Set<id>,
    deleting: Set<id>,
    error?: Error
  },
  insert,
  update,
  remove,
  refetch
}

Multiple queries

{
  [key]: {
    rows,
    state,
    insert,
    update,
    remove
  },

  state: {
    loading: boolean,
    error?: Error,
    connected: boolean
  }
}

πŸ”₯ Key Features

βœ… Real-time SQL subscriptions

Powered by KalamDB SUBSCRIBE TO.

βœ… Dual query mode

  • Drizzle ORM β†’ type-safe
  • SQL β†’ flexible & powerful

βœ… Built-in mutation state

state.inserting
state.updating.has(id)
state.deleting.has(id)

βœ… Multi-query composition

Combine:

  • messages
  • typing events
  • presence
  • notifications

πŸ—οΈ Implementation Notes

  • Built on top of @kalamdb/client

  • Shared logic should live in @kalamdb/client for reuse across frameworks

  • In the future we will be adding other packages for angular vue and other.. so any code which will be repeated better place it inside @kalamdb/client

  • Internally uses:

    • subscribeWithSql() for live updates
    • Drizzle β†’ SQL conversion
  • Must remain UI-agnostic (for future Angular / RN support)


🚧 Future Extensions

@kalamdb/angular

  • @kalamdb/react-native

πŸ’¬ Final Thought

This feature positions KalamDB as:

The first database where UI is directly driven by SQL (or ORM) in React.


πŸ‘ Acceptance Criteria

  • @kalamdb/react package created
  • LiveQuery implemented (Drizzle + SQL modes)
  • LiveQueries implemented
  • Drizzle ORM integration working
  • Raw SQL query mode working
  • Mutation state exposed
  • Multi-query example (chat + typing) working
  • Basic docs + examples added
  • Usable inside Admin UI

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions