Buckets:
| import { Client } from "@planetscale/database" | |
| import { drizzle } from "drizzle-orm/planetscale-serverless" | |
| import { migrate as drizzleMigrate } from "drizzle-orm/planetscale-serverless/migrator" | |
| import { Config, ConfigProvider, Effect, Layer, Schema } from "effect" | |
| import * as Context from "effect/Context" | |
| import * as schema from "./database/schema" | |
| import { Resource } from "sst/resource" | |
| export const DatabaseUrl = Schema.NonEmptyString.pipe(Schema.brand("DatabaseUrl")) | |
| export type DatabaseUrl = typeof DatabaseUrl.Type | |
| export class DatabaseSettings extends Schema.Class<DatabaseSettings>("DatabaseSettings")({ | |
| url: DatabaseUrl, | |
| migrationsDir: Schema.NonEmptyString, | |
| }) {} | |
| const decodeDatabaseSettings = Schema.decodeUnknownSync(DatabaseSettings) | |
| const config = Config.all({ | |
| url: Config.nonEmptyString("DATABASE_URL").pipe(Config.withDefault(Resource.StatsDatabase.url)), | |
| migrationsDir: Config.nonEmptyString("DATABASE_MIGRATIONS_DIR").pipe(Config.withDefault("./migrations")), | |
| }).pipe(Config.map(decodeDatabaseSettings)) | |
| export class DatabaseConfig extends Context.Service<DatabaseConfig, DatabaseSettings>()( | |
| "@opencode/stats/DatabaseConfig", | |
| ) { | |
| static readonly config = config | |
| static readonly layer: Layer.Layer<DatabaseConfig, never, never> = Layer.effect( | |
| DatabaseConfig, | |
| config.parse(ConfigProvider.fromEnv()).pipe(Effect.orDie), | |
| ) | |
| } | |
| function makeDrizzle(settings: DatabaseSettings) { | |
| return drizzle({ client: new Client({ url: settings.url }), schema }) | |
| } | |
| export type Drizzle = ReturnType<typeof makeDrizzle> | |
| export class DrizzleClient extends Context.Service<DrizzleClient, Drizzle>()("@opencode/stats/DrizzleClient") { | |
| static readonly layer: Layer.Layer<DrizzleClient, never, DatabaseConfig> = Layer.effect( | |
| DrizzleClient, | |
| Effect.map(DatabaseConfig, makeDrizzle), | |
| ) | |
| } | |
| export class DatabaseError extends Schema.TaggedErrorClass<DatabaseError>()("DatabaseError", { | |
| cause: Schema.Defect, | |
| }) {} | |
| export const catchDbError = Effect.mapError((cause) => DatabaseError.make({ cause })) | |
| export class MigrationError extends Schema.TaggedErrorClass<MigrationError>()("MigrationError", { | |
| message: Schema.String, | |
| cause: Schema.optional(Schema.Defect), | |
| }) {} | |
| export const migrate = Effect.fn("Database.migrate")(function* () { | |
| const settings = yield* DatabaseConfig | |
| yield* Effect.logInfo("applying database migrations").pipe( | |
| Effect.annotateLogs({ migrationsDir: settings.migrationsDir }), | |
| ) | |
| const result = yield* Effect.tryPromise({ | |
| try: () => | |
| drizzleMigrate(drizzle({ client: new Client({ url: settings.url }) }), { | |
| migrationsFolder: settings.migrationsDir, | |
| }), | |
| catch: (cause) => new MigrationError({ message: "Failed to apply database migrations", cause }), | |
| }) | |
| if (result) | |
| return yield* new MigrationError({ | |
| message: `Failed to initialize database migrations: ${result.exitCode}`, | |
| }) | |
| yield* Effect.logInfo("database migrations complete").pipe( | |
| Effect.annotateLogs({ migrationsDir: settings.migrationsDir }), | |
| ) | |
| }) | |
| export const layer = Layer.mergeAll(DatabaseConfig.layer, DrizzleClient.layer.pipe(Layer.provide(DatabaseConfig.layer))) | |
Xet Storage Details
- Size:
- 3.16 kB
- Xet hash:
- d718406e459d10992f516191f1556ad1f49653aef23dba55b3dd763147a73f74
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.