Database

Databases: SQL for an app or an agent, SQLite by default and Postgres when you outgrow it.

db = noclick.Database.from_name("orders", create_if_missing=True)
db.migrate("migrations/")
db.execute("insert into orders (id, item, qty) values (?, ?, ?)", ["o1", "bun", 3])
for row in db.query("select item, qty from orders where qty > ?", [2]):
    print(row["item"], row["qty"])

The same object serves an app (bound to a project) and an agent keeping its own state. Placeholders are ? with a list, or :name with a dict, on either engine.

class Database

A SQL database: SQLite (the default) or Postgres. query reads, execute and batch write, migrate applies your schema. Database.fromName("orders", { createIfMissing: true }) is lazy. In an agent's or a toolkit's tools it is three tools, {name}__query, {name}__execute and {name}__schema; only(...) picks some of them.

Attributes
idstring
namestring
engineDatabaseEngine

"sqlite" or "postgres".

statusDatabaseStatus

ready, restoring or branching.

sizeBytesnumber | null
tableCountnumber | null
parentIdstring | null

The database a branch was made from (null if it isn't one).

usedByUsedBy[]

Who uses it: apps that bind it (kind project, with the binding name) and agents with it in their tools (kind agent).

regionRegionName | null

The region it keeps its data in, fixed when it was created.

userIdstring | null
workflow{ id: string; name: string | null } | null

The automation whose tables it holds (NoClick makes one for each automation that keeps tables), or null.

createdAtDate | null
consoleUrlstring | null

This database in the developer console (null off the hosted API).

only

only(...operations: DatabaseTool[]): DatabaseOperations

A tool ref to some of its operations, for tools: "query" (a read-only statement), "execute" (a statement that writes) and "schema" (its tables and columns). The database itself in tools gives all three. "upsert" writes one row of one table by its primary key, its parameters that table's columns; bind its table with .bind({ table }).

Parameters
operationsDatabaseTool[]required
Returns

A ref to just those operations, to list in tools=; bind(...) fixes arguments.

createstatic

static create(name: string, options?: DatabaseCreateOptions): Promise<Database>

Create a database, unique by name per user (a taken name throws Conflict with existingId).

Parameters
namestringrequired
options.engineDatabaseEngine

"sqlite" (the default, cheap while idle) or "postgres".

(default "sqlite")
options.regionRegionName

Where it runs or keeps its data (regions()); omitted, your account's default region.

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

The new database, ready and empty.

fromNamestatic

static fromName(
  name: string,
  options?: DatabaseCreateOptions & {
    createIfMissing?: boolean;
    branchData?: BranchData;
  },
): Database

A lazy reference to the database called name for the current (or given) user. With createIfMissing it's created on first use with engine; one that exists is used as it is.

In a preview branch of an app whose preview_resources is branch, the branch gets its own copy at its first write and reads production's as it is until then. A Postgres copy is a copy-on-write branch of production's data; a SQLite copy holds the schema and migrations only (migrate's seed fills it), unless branchData: "copy" asks for production's rows too, read at one moment while production keeps serving (up to 200,000 rows and 16 MB). It changes nothing outside a preview.

Parameters
namestringrequired
options.createIfMissingboolean
options.engineDatabaseEngine

"sqlite" (the default, cheap while idle) or "postgres".

(default "sqlite")
options.regionRegionName

Where it runs or keeps its data (regions()); omitted, your account's default region.

options.branchDataBranchData
options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

A database that loads (or is created) the first time it's used. Nothing is sent yet.

fromIdstatic

static fromId(databaseId: string, options?: CallOptions): Database

A lazy reference to a database by id.

Parameters
databaseIdstringrequired
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
Returns

A database that loads the first time you read a field. Nothing is sent yet.

getstatic

static get(databaseId: string, options?: CallOptions): Promise<Database>

Load a database by id now; an unknown id raises noclick.NotFound.

Parameters
databaseIdstringrequired
options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

The database, loaded: its engine, size, table count and status.

liststatic

static list(
  options?: ReadOptions & { engine?: DatabaseEngine; limit?: number },
): Promise<Database[]>

The current user's databases, branches included (or those userFilter covers).

Parameters
options.engineDatabaseEngine
options.limitnumber

Return at most this many.

options.userFilterUserFilter

Which users the read covers (user_id query), instead of acting as one (user).

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

Every matching database, newest first, fetched page by page.

listPagestatic

static listPage(
  options?: ReadOptions & PageOptions & { engine?: DatabaseEngine },
): Promise<Page<Database>>

One page of databases; pass nextCursor back as cursor.

Parameters
options.cursorstring | null

The next_cursor of the page before; omit it for the first page.

options.limitnumber

Return at most this many.

options.engineDatabaseEngine
options.userFilterUserFilter

Which users the read covers (user_id query), instead of acting as one (user).

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

A page whose data holds the databases and whose next_cursor is None on the last page.

query

query(sql: string, params?: SqlParams): Promise<QueryResult>

Run a read: one select (or with ... select). It runs read-only: a statement that writes throws InvalidRequest; use execute for those. At most 10 MB of rows; 30 seconds. On Postgres, noclick.embed(:q, model) turns a parameter or a quoted text into a halfvec before the statement runs (up to 100 distinct texts a request; not over connectionUrl), so a read (an agent's query tool too) can search by meaning (billed as AI to the database's user).

await kb.query("select id from articles order by embedding <=> noclick.embed(:q, :model) limit 5", { q, model });
Parameters
sqlstringrequired
paramsSqlParams
Returns

The rows as dicts, in rows or by iterating the result, with columns, rows_read and duration_ms.

execute

execute(sql: string, params?: SqlParams): Promise<QueryResult>

Run one statement that writes (several go in a batch). A SQLite database that would pass 10 GB throws QuotaExceeded, whose next step is branching into Postgres.

Parameters
sqlstringrequired
paramsSqlParams
Returns

What it did: rows_written, last_row_id for an insert on SQLite, and the rows a returning clause gave back.

batch

batch(statements: readonly SqlStatement[]): Promise<QueryResult[]>

Run up to 100 statements in one transaction: all apply or none do.

Parameters
statementsreadonly SqlStatement[]required
Returns

One QueryResult per statement, in order.

migrate

migrate(
  migrations: Migrations,
  options?: { dryRun?: boolean; seed?: string },
): Promise<MigrationResult>

Apply the migrations the database hasn't run, in name order, in one transaction (a failing one applies none). In Node, read your migrations/*.sql files into an object first. dryRun reports what would run and changes nothing. seed is SQL run once, after them and in their transaction, on a preview branch's database that holds none of production's data (a SQLite copy made without its rows, or one only the branch has); production never runs it, and it shows in applied as (seed).

Parameters
migrationsMigrationsrequired
options.dryRunboolean
options.seedstring
Returns

The migrations applied now, and those still pending (all the new ones after a dry run).

migrations

migrations(): Promise<Migration[]>

The migrations this database has applied, oldest first.

Returns

Each applied migration with when it ran, oldest first.

schema

schema(): Promise<Table[]>

The database's tables, their columns and row counts.

Returns

Every table by name, each with its columns in order and its row_count.

restore

restore(options: { at: Date | string }): Promise<Operation<Database>>

Put the database back as it was at at (within its history: 30 days on SQLite, 7 on Postgres), in place. wait() resolves to this database, restored. To keep the present, branch at that time instead.

Parameters
options.atDate | stringrequired
Returns

An operation whose wait() gives this database, restored.

branch

branch(
  name: string,
  options?: { at?: Date | string; engine?: DatabaseEngine },
): Promise<Operation<Database>>

Copy the database into a new one called name, as it is now or as it was at (within its history). engine: "postgres" branches SQLite into Postgres. While a SQLite database is copied its status is branching. wait() resolves to the new Database.

Parameters
namestringrequired
options.atDate | string
options.engineDatabaseEngine
Returns

An operation whose wait() gives the new Database.

branches

branches(): Promise<Database[]>

The databases branched from this one.

Returns

Each branch as a Database, newest first.

connectionUrl

connectionUrl(options?: { ttlS?: number; readOnly?: boolean }): Promise<string>

A postgresql:// URL with a password that stops working after ttlS seconds (default 3600), when any session still open on it ends. SQLite throws NotAvailable. Treat it as a secret.

Parameters
options.ttlSnumberdefault 3600
options.readOnlyboolean
Returns

A postgresql:// URL with its short-lived credentials inside; treat it as a secret.

export

export(): Promise<Operation<ExportBundle>>

Export as SQL that recreates its schema and rows in any database of its engine: sqlite3 booking.db < databases/booking-db.sql, or a pg_dump script for psql (NoClick's own noclick schema, owners and grants left out). Exporting a Postgres database wakes it, and its compute is billed as any use is. wait() resolves to an ExportBundle: a zip at url holding the dump.

Returns

An operation whose wait() gives an ExportBundle: a zip at url holding the dump.

delete

delete(): Promise<TrashItem>

Delete the database and its data: it goes to the trash, restorable for 30 days, and its connection URLs stop working. One with branches, an app's binding or an agent's tool throws Conflict. Returns its TrashItem.

Returns

Its TrashItem: restore() puts it back, tables and rows with it.

DatabaseOperations

class DatabaseOperations

Some of a database's operations as tools (db.only(...)), with the arguments bind(...) fixed.

Attributes
databaseDatabase
operationsDatabaseTool[]
bindingsJsonObject

The arguments NoClick fills on every call, out of the model's reach.

bind

bind(args: JsonObject): DatabaseOperations

Fix arguments of these operations, as ConnectionOperations.bind does. upsert needs table bound; bind a column too and every row it writes carries that value.

leads.only("upsert").bind({ table: "enriched" })
Parameters
argsJsonObjectrequired
Returns

A new ref with these arguments bound on top of any bound before.

QueryResult

class QueryResult

What one statement returned: rows (an object per row, keyed by columns), and what it touched (on SQLite the rows read and written, what it's billed on; on Postgres the rows returned and changed, not billed). Iterating it yields the rows. lastRowId is the rowid an insert made on SQLite (null on Postgres, where returning gives it).

Attributes
columnsstring[]
rowsJsonObject[]
rowsReadnumber
rowsWrittennumber
lastRowIdnumber | null
durationMsnumber | null
rawJsonObject

The response JSON exactly as the API sent it.

lengthTypeScript only

length: number

Migration

interface Migration

A migration the database has applied, and the checksum of the SQL that ran.

Attributes
namestring
appliedAtDate | null
checksumstring | null
rawJsonObject

The response JSON exactly as the API sent it.

MigrationResult

interface MigrationResult

What migrate did: what it ran now, and what's still to run (everything new after a dry run).

Attributes
appliedstring[]
pendingstring[]
rawJsonObject

The response JSON exactly as the API sent it.

Table

interface Table

A table: its columns in order and its row count (the planner's estimate on Postgres).

Attributes
namestring
columnsColumn[]
rowCountnumber | null
rawJsonObject

The response JSON exactly as the API sent it.

Column

interface Column

One column of a table. default is its default expression, or null.

Attributes
namestring
typestring
nullableboolean
primaryKeyboolean
defaultstring | null