[data-reveal]{opacity:1!important;transform:none!important}
Database
Database

Query data with AQL

Overview

The Database interface provides AQL (Antelope Query Language), a typed query API for AntelopeJS database providers. Build a query from table access, filters, and transformations, then execute it through the provider bound to your module.

Run your first query

Start in an AntelopeJS module with a configured database provider. Installing the interface supplies query builders and contracts, not a database server or credentials.

  1. Define a schema and create an instance. The schema describes tables; the instance selects where their data lives.
  2. Open a table and compose a read with filtering. Building the query does not execute it.
  3. Execute with await or run(), or consume a cursor for incremental results.
  4. Inspect write results when adding mutations. Inserts return IDs; updates and deletes return counts.

Insert and read one record

Run this function from your module after its database provider is configured. It creates a disposable schema instance and writes one record; do not point this exercise at production data.

import { Schema } from "@antelopejs/interface-database";

interface Note {
  _id: string;
  title: string;
  done: boolean;
}

const notesSchema = new Schema<{ notes: Note }>("notes-demo", {
  notes: {
    fields: { title: "string", done: "boolean" },
    indexes: {},
  },
});

export async function tryNotes() {
  await notesSchema.createInstance("tutorial");
  const notes = notesSchema.instance("tutorial").table("notes");
  const [id] = await notes.insert({ title: "Learn AQL", done: false });
  const saved = await notes.get(id);
  if (!saved) throw new Error("The inserted note was not found");
  return saved.title; // "Learn AQL"
}

notes is a query builder; saved is a fetched record. Calling the function again inserts another record. When you no longer need this disposable data, explicitly run await notesSchema.destroyInstance("tutorial"); it deletes the instance's data.

Find the right reference

QuestionStart with
Which operations fit this query shape?Query types
How do I read and change records?CRUD operations
How do I join related data?Lookup
How do I conditionally change one record?Atomic mutations
What did the provider return?Results

Import Paths

Import Schema, Query, Table, Datum, Stream, and ValueProxy from @antelopejs/interface-database in an AntelopeJS module. This entry point registers schemas with the bound provider and installs query execution (run(), then(), cursor(), and async iteration).

Supporting types have dedicated paths: import Changes, DeepPartial, ExtractType, and Value from @antelopejs/interface-database/common, and FieldType, TableDefinition, and IndexDefinition from @antelopejs/interface-database/schema. Atomic mutation types are available from the package root and /atomic.

Advanced: build queries without executing them

@antelopejs/interface-database/staged-query is the build-only entry point for tools that construct and inspect query stages without the AntelopeJS runtime. Its schema does not register with a provider, and its queries expose build() but no execution methods when loaded on their own. Do not await a build-only query expecting database results. The runtime entry point augments the same staged classes; keep build-only consumers separate from runtime imports when that isolation matters.

Documentation Structure

Features

  • Database-agnostic query interface
  • Consistent API across different database implementations
  • Type-safe operations using TypeScript generics
  • Schema-based database structure definition
  • Multi-instance support per schema
  • Secondary index support
  • Change feeds for real-time updates
  • Async iteration with cursor support
  • Chainable query builder with lazy evaluation

Database Interoperability

AQL separates query construction from the database engine. A provider translates the shared operations into its backend's behavior. Before moving an application between providers, check that provider's supported operations and exercise the queries, indexes, and change feeds your application uses; a shared TypeScript contract is not a guarantee of identical backend capabilities or performance.