Skip to content

SQL Databases ​

Nostrify can store events in Postgres, SQLite, and more thanks to Kysely.

The NDatabase class accepts a Kysely instance and then executes queries on it. First create a Kysely instance and connect it to whichever database you choose, then pass it to NDatabase.

ts
const kysely = new Kysely(/* set up your database */);

const db = new NDatabase(kysely);
await db.migrate();

Usage ​

NDatabase implements NStore, allowing you to use it interchangeably with relays.

Insert an event ​

ts
await db.event(event);

Query events ​

ts
const events = await db.query([{ kinds: [1, 6], limit: 5 }]);

Count events ​

ts
const { count } = await db.count([{ kinds: [1, 6] }]);

Remove events ​

ts
await db.remove([{ kinds: [1, 6] }]);

NDatabase supports NIP-50 search with the fts option:

ts
const db = new NDatabase(kysely, {
  fts: 'postgres', // can be 'postgres' or 'sqlite'
});

Search filters ​

Once enabled, you can query with search filters:

ts
const events = await db.query([{ kinds: [1], search: 'hello world' }]);

NOTE

If FTS is not enabled, the search filter will always return an empty array.

Tables ​

NDatabase manages two tables:

  • nostr_events stores Nostr events. Each property has its own column.
  • nostr_tags stores tags to be indexed for tag filters.

TIP

By default, all single-letter tags are indexed. You can customize this behavior by passing a custom indexTags function into NDatabase.

NOTE

If FTS is enabled, one of the following tables will also be created:

  • nostr_pgfts to store the Postgres search index.
  • nostr_fts5 to store the SQLite search index.

Migrating the database ​

Run await db.migrate() to create the necessary tables and indexes before use. You should call this every time the program starts.

SQLite on Deno ​

Using @db/sqlite and @soapbox/kysely-deno-sqlite, you can connect to an SQLite database in Deno.

ts
import { Database } from '@db/sqlite';
import { DenoSqlite3Dialect } from '@soapbox/kysely-deno-sqlite';
import { Kysely } from 'kysely';

const kysely = new Kysely({
  dialect: new DenoSqlite3Dialect({
    database: new Database('./nostr.sqlite3'),
  }),
});

const db = new NDatabase(kysely);
await db.migrate();

Postgres on Deno ​

Using x/kysely_deno_postgres you can connect to a Postgres database in Deno.

ts
import { NDatabase } from '@nostrify/nostrify';
import { PostgreSQLDriver } from 'https://deno.land/x/[email protected]/mod.ts';
import { Kysely, PostgresAdapter, PostgresIntrospector, PostgresQueryCompiler } from 'kysely';

const kysely = new Kysely({
  dialect: {
    createAdapter() {
      return new PostgresAdapter();
    },
    // @ts-ignore mismatched kysely versions probably
    createDriver() {
      return new PostgreSQLDriver({
        database: 'test',
        hostname: 'localhost',
        user: 'postgres',
        password: 'postgres',
        port: 5432,
      });
    },
    createIntrospector(db: Kysely<unknown>) {
      return new PostgresIntrospector(db);
    },
    createQueryCompiler() {
      return new PostgresQueryCompiler();
    },
  },
});

const db = new NDatabase(kysely);
await db.migrate();

TIP

There are a few different Postgres drivers for Deno. See which one works best for you.

Other databases ​

Kysely maintains a list of supported dialects.

It may be possible to get other dialects working. Or build your own!

Soapbox