-
Notifications
You must be signed in to change notification settings - Fork 573
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
25 changed files
with
596 additions
and
242 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
import assert from 'assert' | ||
import { | ||
Kysely, | ||
SqliteDialect, | ||
Migrator, | ||
KyselyPlugin, | ||
PluginTransformQueryArgs, | ||
PluginTransformResultArgs, | ||
RootOperationNode, | ||
QueryResult, | ||
UnknownRow, | ||
} from 'kysely' | ||
import SqliteDB from 'better-sqlite3' | ||
import { DatabaseSchema } from './schema' | ||
import * as migrations from './migrations' | ||
import { CtxMigrationProvider } from './migrations/provider' | ||
|
||
export class UserDb { | ||
migrator: Migrator | ||
destroyed = false | ||
|
||
constructor(public db: Kysely<DatabaseSchema>) { | ||
this.migrator = new Migrator({ | ||
db, | ||
provider: new CtxMigrationProvider(migrations), | ||
}) | ||
} | ||
|
||
static sqlite(location: string): UserDb { | ||
const db = new Kysely<DatabaseSchema>({ | ||
dialect: new SqliteDialect({ | ||
database: new SqliteDB(location), | ||
}), | ||
}) | ||
return new UserDb(db) | ||
} | ||
|
||
static memory(): UserDb { | ||
return UserDb.sqlite(':memory:') | ||
} | ||
|
||
async transaction<T>(fn: (db: UserDb) => Promise<T>): Promise<T> { | ||
const leakyTxPlugin = new LeakyTxPlugin() | ||
return this.db | ||
.withPlugin(leakyTxPlugin) | ||
.transaction() | ||
.execute(async (txn) => { | ||
const dbTxn = new UserDb(txn) | ||
const txRes = await fn(dbTxn) | ||
.catch(async (err) => { | ||
leakyTxPlugin.endTx() | ||
// ensure that all in-flight queries are flushed & the connection is open | ||
await dbTxn.db.getExecutor().provideConnection(async () => {}) | ||
throw err | ||
}) | ||
.finally(() => leakyTxPlugin.endTx()) | ||
return txRes | ||
}) | ||
} | ||
|
||
get isTransaction() { | ||
return this.db.isTransaction | ||
} | ||
|
||
assertTransaction() { | ||
assert(this.isTransaction, 'Transaction required') | ||
} | ||
|
||
assertNotTransaction() { | ||
assert(!this.isTransaction, 'Cannot be in a transaction') | ||
} | ||
|
||
async close(): Promise<void> { | ||
if (this.destroyed) return | ||
await this.db.destroy() | ||
this.destroyed = true | ||
} | ||
|
||
async migrateToOrThrow(migration: string) { | ||
const { error, results } = await this.migrator.migrateTo(migration) | ||
if (error) { | ||
throw error | ||
} | ||
if (!results) { | ||
throw new Error('An unknown failure occurred while migrating') | ||
} | ||
return results | ||
} | ||
|
||
async migrateToLatestOrThrow() { | ||
const { error, results } = await this.migrator.migrateToLatest() | ||
if (error) { | ||
throw error | ||
} | ||
if (!results) { | ||
throw new Error('An unknown failure occurred while migrating') | ||
} | ||
return results | ||
} | ||
} | ||
|
||
class LeakyTxPlugin implements KyselyPlugin { | ||
private txOver: boolean | ||
|
||
endTx() { | ||
this.txOver = true | ||
} | ||
|
||
transformQuery(args: PluginTransformQueryArgs): RootOperationNode { | ||
if (this.txOver) { | ||
throw new Error('tx already failed') | ||
} | ||
return args.node | ||
} | ||
|
||
async transformResult( | ||
args: PluginTransformResultArgs, | ||
): Promise<QueryResult<UnknownRow>> { | ||
return args.result | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
packages/pds/src/user-db/migrations/20230613T164932261Z-init.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { Kysely } from 'kysely' | ||
|
||
export async function up(db: Kysely<unknown>): Promise<void> {} | ||
|
||
export async function down(db: Kysely<unknown>): Promise<void> {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
// NOTE this file can be edited by hand, but it is also appended to by the migration:create command. | ||
// It's important that every migration is exported from here with the proper name. We'd simplify | ||
// this with kysely's FileMigrationProvider, but it doesn't play nicely with the build process. | ||
|
||
export * as _20230613T164932261Z from './20230613T164932261Z-init' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { Kysely, Migration, MigrationProvider } from 'kysely' | ||
|
||
// @TODO remove/cleanup | ||
|
||
// Passes a context argument to migrations. We use this to thread the dialect into migrations | ||
|
||
export class CtxMigrationProvider implements MigrationProvider { | ||
constructor(private migrations: Record<string, CtxMigration>) {} | ||
async getMigrations(): Promise<Record<string, Migration>> { | ||
const ctxMigrations: Record<string, Migration> = {} | ||
Object.entries(this.migrations).forEach(([name, migration]) => { | ||
ctxMigrations[name] = { | ||
up: async (db) => await migration.up(db), | ||
down: async (db) => await migration.down?.(db), | ||
} | ||
}) | ||
return ctxMigrations | ||
} | ||
} | ||
|
||
export interface CtxMigration { | ||
up(db: Kysely<unknown>): Promise<void> | ||
down?(db: Kysely<unknown>): Promise<void> | ||
} |
File renamed without changes.
1 change: 0 additions & 1 deletion
1
packages/pds/src/db/tables/blob.ts → packages/pds/src/user-db/schema/blob.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,4 @@ | ||
export interface Blob { | ||
creator: string | ||
cid: string | ||
mimeType: string | ||
size: number | ||
|
Oops, something went wrong.