# gizdb:store

the database a web app keeps its records in, one call shape over three engines. GizDB is the default: a folder, whose engine this process serves (other processes, a worker or the platform, reach it at the folder's unix socket with its password). DATABASE_URL selects another: PostgreSQL (a server; each worker process holds a pool) or a SQLite file (embedded; every worker process opens it). Apps, the feed and the model write one SQL for all (ON CONFLICT, RETURNING, $N, TRUE and FALSE); what differs, DDL types and locks, is chosen here or by the SQL Dialect (db/sql/types/dialect.giz). Typed records (db/data.giz) use the same GizDB engine through db/access.giz.

```gizlang
import * as Store from "gizdb:store";
```

## Types

### `Engine`

```gizlang
type Engine = { endpoint: Access.Endpoint; identity: string; secret: bytes; }
```

The GizDB engine this process serves for a folder: the endpoint typed
connections reach it at from any thread (Data.of).

- `endpoint`: `M47.Endpoint`
- `identity`: `string`
- `secret`: `bytes`

### `Served`

```gizlang
type Served = { engine: Engine; server: Task.Task<Result<i64, string>>; }
```

A GizDB engine of this process: how it is reached, and its server task.

- `engine`: `M51.Engine`
- `server`: `gizlang_task.Task<_gizlang_sdk_core.Result<i64, string>>`

### `Folder`

```gizlang
type Folder = { pool: Pg.Pool; served: Option<Served>; }
```

A GizDB folder open in this process: its pool, and its engine when this process serves it.

- `pool`: `gizlang_postgres.Pool`
- `served`: `_gizlang_sdk_core.Option<M51.Served>`

### `Database`

```gizlang
type Database = | { kind: "gizdb"; folder: Ref<Folder>; } | { kind: "sqlite"; db: Sqlite.Database; } | { kind: "postgres"; pool: Pg.Pool; } | { kind: "session"; connection: Pg.Connection; }
```

A database: a GizDB folder (its pool, and its engine when this process
serves it), a SQLite file, a PostgreSQL pool, or inside a transaction the
one PostgreSQL connection it runs on.

- `gizdb`
- `sqlite`
- `postgres`
- `session`

### `Rows`

```gizlang
type Rows = { rows: Vec<Vec<Option<string>>>; affected: i64; }
```

A statement's rows, each column as text and none for NULL, and the rows
an INSERT, UPDATE or DELETE without RETURNING changed.

- `rows`: `Vec<Vec<_gizlang_sdk_core.Option<string>>>`
- `affected`: `i64`

### `StoreError`

```gizlang
type StoreError = { sqlstate: Option<string>; message: string; detail: string; position: Option<i64>; code: i64; }
```

A store failure. PostgreSQL fills `sqlstate`, `detail` and `position` from
the server's error; SQLite has none of them. `code` is the engine's own
number (the SQLite extended result code, a transport errno), else 0.

- `sqlstate`: `_gizlang_sdk_core.Option<string>`
- `message`: `string`
- `detail`: `string`
- `position`: `_gizlang_sdk_core.Option<i64>`
- `code`: `i64`

### `Selected`

```gizlang
type Selected = { columns: Vec<string>; rows: Vec<Vec<Option<string>>>; }
```

A query's result with its column names: for a reader of any result (the Giz Data console).

- `columns`: `Vec<string>`
- `rows`: `Vec<Vec<_gizlang_sdk_core.Option<string>>>`

### `Moved`

```gizlang
type Moved = { same: bool; lines: Vec<string>; }
```

What a move found: `same` when every table is equal, and a line for each table.

- `same`: `bool`
- `lines`: `Vec<string>`

## Functions

### `flag`

```gizlang
function flag(text: string): bool
```

A boolean column of `Rows`: SQLite spells true "1", PostgreSQL "t".

### `storeError`

```gizlang
function storeError(message: string): StoreError
```

A storage error with MESSAGE only.

### `integer`

```gizlang
function integer(text: Option<string>): Result<i64, StoreError>
```

An integer column of `Rows` (decimal in both engines). NULL, or text
that is not an i64, is an error, never a silent 0.

Effects: fail.

### `open`

```gizlang
function open(sys: System, location: string): Result<Database, StoreError>
```

`location` is postgres://USER:PASSWORD@HOST:PORT/DATABASE (no percent
escapes; as libpq, a trailing ?host=/FOLDER names the folder of the
server's unix-domain socket instead of HOST, which may then be empty), a
SQLite file (a path that ends in .db, or :memory:), else a GizDB folder
(made when missing; see gizdb). STORE_QUOTA, when set, is the most bytes
a GizDB or SQLite store holds: past it a write fails and reads go on.
A SQLite file is opened as each worker process (GIZLANG_WORKERS) needs
it: WAL, so readers never wait for the writer; a writer that finds
another worker's write in progress waits up to 5 s for it instead of
failing; commits sync at checkpoints (synchronous NORMAL: a power loss
may drop the last commits, never corrupt).

Effects: fail, read, write, console, io.

### `gizdbLocation`

```gizlang
function gizdbLocation(sys: System, folder: string, password: string): string
```

The postgres:// location of the GizDB server of `folder` (absolute) with `password`.

Effects: fail, io.

### `gizdbSocket`

```gizlang
function gizdbSocket(sys: System, folder: string): string
```

The path to listen and connect at for the socket folder GIZDB_RUN of `folder` (absolute).

Effects: fail, io.

### `socketFolder`

```gizlang
function socketFolder(sys: System, folder: string): string
```

The path of `folder` (absolute) for its unix-domain sockets (GIZDB_RUN, a hosted app's platform socket).
The socket files are always in the folder (a hosted app reaches them there), but a socket path may be at
most 107 bytes. For a deep folder this is /tmp/giz-HASH (the folder's SHA-256), a link to it that this makes.

Effects: fail, io.

### `serving`

```gizlang
function serving(sys: System, folder: string): bool
```

Whether a process serves the GizDB folder `folder` now.

Effects: fail, io.

### `identityColumn`

```gizlang
function identityColumn(dialect: Dialect, name: string): string
```

The DDL of column `name`: an i64 primary key that the database numbers upward on each INSERT and never hands out again.

Effects: fail.

### `move`

```gizlang
function move(src: Database, dst: Database, verify: bool): Result<Moved, StoreError>
```

Move the SQLite database `src` into `dst`, which has none of its tables,
and prove the copy; with `verify`, only compare an earlier copy.

Effects: fail, read, write, console, io.

### `conflictError`

```gizlang
function conflictError(message: string): StoreError
```

A failed guard (a write that had to change an exact number of rows): a serialization conflict, as the transaction's caller reads it.

### `stored`

```gizlang
function stored<T>(r: Result<T, StoreError>): Result<T, string>
```

A store result whose failure is the text of its error.

### `migrate`

```gizlang
function migrate(db: Database, shape: Model.Shape): Result<Rows, StoreError>
```

Bring the table up to the shape, additively: create it, add each missing
column (a required one with an empty, zero or false default for the rows
already there) and the indexes. A column the shape no longer has keeps its
data: dropping or converting is an explicit, separate step. One transaction
under the table's lock, so worker processes starting together migrate one
after another (PostgreSQL's CREATE TABLE IF NOT EXISTS is not safe to race).
The result's `affected` counts the statements that changed the schema.

Effects: fail, read, write, console, io.

### `migrateLocked`

```gizlang
function migrateLocked(tx: Database, shape: Model.Shape): Result<Rows, StoreError>
```

Within the caller's locked transaction: @was, additive columns, then indexes.

Effects: fail, read, write, console, io.

### `records`

```gizlang
function records<T>(db: Database, tail: string, params: Vec<Option<string>>): Result<Vec<T>, StoreError>
```

The records of the stored type T that `tail` (the SQL after "FROM TABLE", such as "WHERE org = $1 ORDER BY created")
finds with `params`. A Gate-checked read is `Data.find`; `one` answers a 404 when there is none.

### `recordsOf`

```gizlang
function recordsOf<T>(found: Rows): Vec<T>
```

The records T of rows whose columns are `columns(shape<T>())`, such as an `UPDATE ... RETURNING` answer.

### `record`

```gizlang
function record<T>(db: Database, tail: string, params: Vec<Option<string>>): Result<Option<T>, StoreError>
```

The first record that `records` finds, if any.

### `one`

```gizlang
function one<T>(db: Database, tail: string, params: Vec<Option<string>>, message: string): Result<T, Model.Rejection>
```

The record that `record` finds, or a 404 with `message` (as `Data.one`).

### `insert`

```gizlang
function insert<T>(db: Database, shape: Model.Shape, record: T): Result<Rows, StoreError>
```

Insert one record of a stored Shape into a SQL store (or inside its transaction). A Gate-checked write is `Data.insert`.

## Methods

### `Database.dialect`

```gizlang
function Database.dialect(self: Database): Dialect
```

The SQL a Database speaks.

Effects: fail.

### `Database.query`

```gizlang
function Database.query(self: Database, sql: string, params: Vec<Option<string>>): Result<Rows, StoreError>
```

One statement with parameters $1.. (none for NULL).

Effects: fail, read, write, console, io.

### `Database.select`

```gizlang
function Database.select(self: Database, sql: string, params: Vec<Option<string>>): Result<Selected, StoreError>
```

One statement with parameters $1.., its rows with their column names.

Effects: fail, read, write, console, io.

### `Database.exec`

```gizlang
function Database.exec(self: Database, sql: string): Result<bool, StoreError>
```

A script of statements without parameters or results.

Effects: fail, read, write, console, io.

### `Database.transaction`

```gizlang
function Database.transaction<F>(self: Database, work: F): ReturnType<F>
```

Runs an application callback once. Commit conflicts are returned with their
SQLSTATE; an application effect is never implicitly replayed.

### `Database.lock`

```gizlang
function Database.lock(self: Database, name: string): Result<bool, StoreError>
```

Inside a transaction: the lock named `name` until it ends, so transactions
taking the same name run one after another while readers go on reading
(the name need not be a table yet). SQLite's writers already run one after
another; PostgreSQL takes a transaction advisory lock on the name (GizDB
checks it at commit: see Database.transaction).

Effects: fail, read, write, io.

### `Database.columns`

```gizlang
function Database.columns(self: Database, table: string): Result<Vec<string>, StoreError>
```

The names of a table's columns; none when it does not exist.

Effects: fail, read, write, console, io.

### `Database.tables`

```gizlang
function Database.tables(self: Database): Result<Vec<string>, StoreError>
```

The names of the tables in the current schema, in order.

Effects: fail, read, write, console, io.

### `Database.engine`

```gizlang
function Database.engine(self: Database): Option<Engine>
```

The GizDB engine this process serves for the database, which typed
records reach from any thread (db/data.giz of); none for another engine
or a folder that another process serves.

Effects: fail, read.

### `Database.close`

```gizlang
function Database.close(self: Database): void
```

Close the database (a pool waits for its lent connections to come back;
the GizDB engine this process serves stops after it).

Effects: fail, read, write, io.

### `StoreError.conflicting`

```gizlang
function StoreError.conflicting(self: StoreError): bool
```

True when the write lost to another or broke a key or constraint: PostgreSQL class 23 (integrity) or 40 (rollback), SQLite's constraint code.

Effects: fail.

### `StoreError.text`

```gizlang
function StoreError.text(self: StoreError): string
```

The failure as one line: its message, then its detail when it has one.

Effects: fail.

### `StoreError.rejection`

```gizlang
function StoreError.rejection(self: StoreError): Model.Rejection
```

The error as a rejection that a request answers: status 500 with the message.

Effects: fail.

## Constants

### `GIZDB_FILES`

```gizlang
const GIZDB_FILES = ".gizdb"
```

The engine's files.

### `GIZDB_RUN`

```gizlang
const GIZDB_RUN = ".gizdb.run"
```

The folder of its one way in, the unix socket .s.PGSQL.5432 (libpq's name); no TCP port is open.

### `GIZDB_PASSWORD`

```gizlang
const GIZDB_PASSWORD = ".gizdb.pw"
```

Its password: gizdb without one would accept every client.

### `GIZDB_MOVED`

```gizlang
const GIZDB_MOVED = ".gizdb.moved"
```

The record that its first start moved the folder's SQLite file in, or found none.

