Skip to main content

Data Adapters

A data adapter is how a language reads a registered source. Each provided language has a default one; write your own when your data has a different shape: Map-backed rows, a different graph library, a tree that is not a DOM.

An adapter is a plain object, so it does not need to be a class, and you pass it in the language's config.

A worked example: Map-backed SQL rows

SQLDataAdapter has two members:

  • createColumnAccessor(prop) returns a function that reads one column out of a row. This is called once per referenced column at plan time, not per row.
  • createRow(keys, values) builds a row of the same shape from parallel arrays. The engine needs it whenever it constructs rows itself.

Both are needed. Implementing only the accessor works until the first query that builds a row, and then fails in a way that is hard to trace back here.

import { DortDB } from '@dortdb/core';
import { defaultRules } from '@dortdb/core/optimizer';
import { SQL, type SQLDataAdapter } from '@dortdb/lang-sql';

const mapAdapter: SQLDataAdapter<Map<string, unknown>> = {
createColumnAccessor: (prop) => (row) => row.get(prop as string),
createRow: (keys, values) => new Map(keys.map((k, i) => [k, values[i]])),
};

const db = new DortDB({
mainLang: SQL({ adapter: mapAdapter }),
optimizer: { rules: defaultRules },
});

db.registerSource(
['users'],
[
new Map([
['name', 'Alice'],
['age', 30],
]),
new Map([
['name', 'Bob'],
['age', 25],
]),
],
);

db.query(
'SELECT users.name AS name, users.age AS age FROM users WHERE users.age > 27',
);
// data: [{ name: 'Alice', age: 30 }]

The rows going in are Maps; the rows coming out are ordinary objects, because the result is serialized back to plain JavaScript values before it is returned.

The other two languages

The interfaces differ per language, because the data models do:

LanguageInterfaceWhat you implement
SQLSQLDataAdapterreading a column from a row, and building a row
CypherCypherDataAdapterenumerating and filtering nodes and edges, and traversing between them
XQueryXQueryDataAdapterstepping along the XPath axes, and constructing nodes

The provided ObjectDataAdapter, GraphologyDataAdapter, and DomDataAdapter are the worked references for each; the Cypher and XQuery interfaces are considerably larger than SQL's, so extending the provided class and overriding what differs is usually less work than starting from scratch.