@statelyjs/arrow

Apache Arrow data visualization plugin for Stately.

npm License

Provides streaming SQL query execution, table visualization, and connector management for Arrow-based data sources.

Overview

This package connects your application to a stately-arrow backend (Rust), giving you:

  • Arrow Viewer page - Full-featured SQL query editor with streaming results
  • Connector management - Browse and register data source connections
  • Streaming queries - Execute SQL with real-time result streaming
  • Arrow table visualization - High-performance table rendering with pagination and column controls

Installation

pnpm add @statelyjs/arrow

Quick Start

1. Add Schema Plugin

import { stately } from '@statelyjs/stately/schema';
import { type ArrowPlugin, arrowPlugin } from '@statelyjs/arrow';

const schema = stately<MySchemas, readonly [ArrowPlugin]>(openapiDoc, PARSED_SCHEMAS)
  .withPlugin(arrowPlugin());

2. Add UI Plugin

import { statelyUi } from '@statelyjs/stately';
import { type ArrowUiPlugin, arrowUiPlugin } from '@statelyjs/arrow';

const runtime = statelyUi<MySchemas, readonly [ArrowUiPlugin]>({
  schema,
  client,
  core: { api: { pathPrefix: '/entity' } },
  options: { api: { pathPrefix: '/api' } },
}).withPlugin(arrowUiPlugin({
  api: { pathPrefix: '/arrow' },
}));

3. Wrap Your App

import { QueryClientProvider } from '@tanstack/react-query';
import { AppStatelyProvider, runtime } from './lib/stately';

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <AppStatelyProvider runtime={runtime}>
        <YourApp />
      </AppStatelyProvider>
    </QueryClientProvider>
  );
}

4. Configure Styles

Import the arrow styles and ensure your @source covers @statelyjs packages:

@import "tailwindcss";
@import "@statelyjs/stately/styles.css";
@import "@statelyjs/arrow/styles.css";

@source "./node_modules/@statelyjs";

Adding Routes

The plugin provides an ArrowViewer page component. Add it to your router:

import { ArrowViewer } from '@statelyjs/arrow/pages';

// Example with React Router
<Route path="/data" element={<ArrowViewer />} />

Hooks

All hooks use the arrow API through the plugin context:

useStreamingQuery

Execute SQL queries with streaming results:

import { useStreamingQuery } from '@statelyjs/arrow/hooks';

function QueryRunner() {
  const { snapshot, execute, isPending, isStreaming } = useStreamingQuery();

  const handleRun = () => {
    execute({
      connector_id: 'my-connector',
      sql: 'SELECT * FROM users LIMIT 100',
    });
  };

  return (
    <div>
      <button onClick={handleRun} disabled={isPending || isStreaming}>
        Run Query
      </button>
      {snapshot.table && (
        <p>Rows: {snapshot.table.numRows}, Bytes: {snapshot.metrics.bytesReceived}</p>
      )}
    </div>
  );
}

useConnectors

Manage connector state and selection:

import { useConnectors } from '@statelyjs/arrow/hooks';

function ConnectorPicker() {
  const { connectors, currentConnector, setConnectorId } = useConnectors();

  return (
    <select
      value={currentConnector?.id}
      onChange={e => setConnectorId(e.target.value)}
    >
      {connectors.map(c => (
        <option key={c.id} value={c.id}>{c.name}</option>
      ))}
    </select>
  );
}

useListConnectors

Fetch available connectors:

import { useListConnectors } from '@statelyjs/arrow/hooks';

const { data: connectors, isLoading } = useListConnectors();

useListRegistered

Get registered catalog connections:

import { useListRegistered } from '@statelyjs/arrow/hooks';

const { data: registrations } = useListRegistered();

useConnectionDetails

Get details for a specific connector:

import { useConnectionDetails } from '@statelyjs/arrow/hooks';

const { data: details } = useConnectionDetails(connectorId);

useRegisterConnection

Register a new connection:

import { useRegisterConnection } from '@statelyjs/arrow/hooks';

const { mutate: register } = useRegisterConnection();
register({ connectorId: 'postgres-1' });

useListCatalogs

List available catalogs:

import { useListCatalogs } from '@statelyjs/arrow/hooks';

const { data: catalogs } = useListCatalogs();

Components

Reusable components for building data interfaces:

ArrowTable

High-performance table for Arrow data:

import { ArrowTable } from '@statelyjs/arrow/components';

<ArrowTable
  data={tableDataView}
  isLoading={isStreaming}
/>

QueryEditor

SQL editor with run controls and stats:

import { QueryEditor } from '@statelyjs/arrow/components';

<QueryEditor
  sql={sql}
  onSql={setSql}
  onRun={handleRun}
  isExecuting={isPending}
  stats={[
    { label: SquareSigma, value: '1,234' },
    { label: Timer, value: '45.2 ms' },
  ]}
/>

TablePagination

Pagination controls for tables:

import { TablePagination } from '@statelyjs/arrow/components';

<TablePagination table={reactTable} />

TableViewOptions

Column visibility toggles:

import { TableViewOptions } from '@statelyjs/arrow/components';

<TableViewOptions table={reactTable} />

TableRowDrawer

Drawer for viewing row details:

import { TableRowDrawer } from '@statelyjs/arrow/components';

<TableRowDrawer row={selectedRow} onClose={handleClose} />

Views

Pre-built view cards for common layouts:

Connectors

import { Connectors } from '@statelyjs/arrow/views';

// Connector selection dropdown
<Connectors.ConnectorSelectCard
  connectors={connectors}
  currentConnector={selected}
  onSelect={handleSelect}
/>

// Connector browser with schema navigation
<Connectors.ConnectorMenuCard
  connectors={connectors}
  currentConnector={selected}
  onSelectItem={(identifier, type) => { /* handle table/schema selection */ }}
/>

// Registration card
<Connectors.ConnectorsRegisterCard
  connectors={connectors}
  currentConnector={selected}
/>

Query

import { Query } from '@statelyjs/arrow/views';

// Query editor card
<Query.QueryEditorCard
  sql={sql}
  onSql={setSql}
  onRun={handleRun}
  isExecuting={isPending}
/>

// Results table card
<Query.QueryResultsCard
  data={tableDataView}
  isLoading={isStreaming}
/>

Pages

ArrowViewer

Full-featured data exploration page with:

  • Connector sidebar with schema browser
  • SQL query editor with syntax highlighting
  • Streaming results table with pagination
  • Query statistics (rows, bytes, elapsed time)
  • Responsive layout with collapsible sidebar
import { ArrowViewer } from '@statelyjs/arrow/pages';

// Basic usage
<Route path="/data" element={<ArrowViewer />} />

// With streaming subscription
<ArrowViewer subscribe={(event) => console.log('Stream event:', event)} />

Library Utilities

Low-level utilities for custom implementations:

createArrowTableStore

Store for managing Arrow table state:

import { createArrowTableStore } from '@statelyjs/arrow/lib';

const store = createArrowTableStore();
store.subscribe(snapshot => {
  console.log('Table updated:', snapshot.table?.numRows);
});

streamQuery

Execute streaming queries directly:

import { streamQuery } from '@statelyjs/arrow/lib';

await streamQuery({
  client,
  sql: 'SELECT * FROM users',
  connectorId: 'my-connector',
  onBatch: (table) => console.log('Batch:', table.numRows),
});

tableToDataView

Convert Arrow table to component-friendly format:

import { tableToDataView } from '@statelyjs/arrow/lib';

const view = tableToDataView(arrowTable);
// { columns: [...], rows: [...] }

Backend Requirements

This plugin expects a stately-arrow compatible backend with these endpoints:

EndpointMethodDescription
/connectorsGETList available connectors
/connectorsPOSTGet details for multiple connectors
/connectors/{connector_id}GETGet connector details
/registerGETList registered connections
/register/{connector_id}GETRegister a connector
/catalogsGETList available catalogs
/queryPOSTExecute SQL query (streaming response)

The /query endpoint returns Apache Arrow IPC stream format for efficient data transfer.

License

Apache-2.0

Modules