Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | 1x 1x 1x 1x 1x 60x 60x 60x 1x 60x 60x 60x 60x 60x 60x 60x 60x 180x 3x 3x 177x 177x 177x 177x 177x 177x 177x 177x 177x 177x 177x 177x 177x 60x 60x | import type { Client } from '@libsql/client';
import { info } from '@shared/console-logging';
import { ensureForeignKeys } from './client';
import { type LibsqlMigration, libsqlMigrations } from './schema';
/**
* Mirrors the Postgres tracking table that
* `docker/postgres/migrations/run-migrations.sh` maintains, so both backends
* answer "which migrations have been applied" the same way.
*/
const SCHEMA_MIGRATIONS = `
CREATE TABLE IF NOT EXISTS schema_migrations (
version TEXT PRIMARY KEY,
applied_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
)`;
const appliedVersions = async (client: Client): Promise<Set<string>> => {
const result = await client.execute('SELECT version FROM schema_migrations');
return new Set(result.rows.map((row) => String(row.version)));
};
/**
* Apply any migrations this database has not seen.
*
* Each migration goes through `batch(..., 'write')`, which wraps its statements
* in a single transaction: a migration either lands completely or not at all,
* and its `schema_migrations` row is written inside the same transaction so the
* two can never disagree.
*
* Unlike the Postgres runner there is no advisory lock. A local database has a
* single writer by definition, and for a remote one the `CREATE TABLE IF NOT
* EXISTS` / `INSERT OR IGNORE` shape means a concurrent second runner converges
* on the same result rather than corrupting anything.
*/
export const migrateLibsql = async (
client: Client,
migrations: LibsqlMigration[] = libsqlMigrations,
): Promise<string[]> => {
await ensureForeignKeys(client);
await client.execute(SCHEMA_MIGRATIONS);
const applied = await appliedVersions(client);
const ran: string[] = [];
for (const migration of migrations) {
if (applied.has(migration.version)) {
continue;
}
await client.batch(
[
...migration.statements,
{
sql: 'INSERT OR IGNORE INTO schema_migrations (version) VALUES (?)',
args: [migration.version],
},
],
'write',
);
ran.push(migration.version);
info(`[libsql] applied migration ${migration.version}`);
}
return ran;
};
|