Merge commit '36c66dd290d3ce6eb1ccd310d0c658d4a32bb8eb' as 'repos/effect'

This commit is contained in:
-Puter
2026-07-19 03:25:10 +05:30
parent dd1071cc10
commit 2daf979036
2214 changed files with 673090 additions and 0 deletions

View File

@@ -0,0 +1,149 @@
import { PgliteClient } from "@effect/sql-pglite"
import { assert, describe, layer } from "@effect/vitest"
import * as Pglite from "@electric-sql/pglite"
import { Deferred, Effect, Layer } from "effect"
import { SqlClient } from "effect/unstable/sql/SqlClient"
const ClientLayer = PgliteClient.layer()
const Migrations = Layer.effectDiscard(
Effect.gen(function*() {
const sql = yield* SqlClient
yield* sql`DROP TABLE test`.pipe(Effect.ignore)
yield* sql`CREATE TABLE test (id SERIAL PRIMARY KEY, name TEXT)`
})
)
describe("PgliteClient", () => {
layer(ClientLayer, { timeout: "30 seconds" })((it) => {
it.effect("basic insert/select", () =>
Effect.gen(function*() {
const sql = yield* PgliteClient.PgliteClient
yield* sql`INSERT INTO test (name) VALUES ('hello')`
const rows = yield* sql<{ id: number; name: string }>`SELECT * FROM test`
assert.deepStrictEqual(rows, [{ id: 1, name: "hello" }])
const values = yield* sql`SELECT * FROM test`.values
assert.deepStrictEqual(values, [[1, "hello"]])
}).pipe(Effect.provide(Migrations)))
it.effect("insert helper", () =>
Effect.gen(function*() {
const sql = yield* PgliteClient.PgliteClient
const [query, params] = sql`INSERT INTO people ${sql.insert({ name: "Tim", age: 10 })}`.compile()
assert.strictEqual(query, `INSERT INTO people ("name","age") VALUES ($1,$2)`)
assert.deepStrictEqual(params, ["Tim", 10])
}))
it.effect("update helper", () =>
Effect.gen(function*() {
const sql = yield* PgliteClient.PgliteClient
const [query, params] = sql`UPDATE people SET ${sql.update({ name: "Tim" })}`.compile()
assert.strictEqual(query, `UPDATE people SET "name" = $1`)
assert.deepStrictEqual(params, ["Tim"])
}))
it.effect("updateValues helper", () =>
Effect.gen(function*() {
const sql = yield* PgliteClient.PgliteClient
const [query, params] = sql`UPDATE people SET name = data.name FROM ${
sql.updateValues([{ name: "Tim" }, { name: "John" }], "data")
}`.compile()
assert.strictEqual(
query,
`UPDATE people SET name = data.name FROM (values ($1),($2)) AS data("name")`
)
assert.deepStrictEqual(params, ["Tim", "John"])
}))
it.effect("in helper", () =>
Effect.gen(function*() {
const sql = yield* PgliteClient.PgliteClient
const [query, params] = sql`SELECT * FROM ${sql("people")} WHERE id IN ${sql.in([1, 2, "x"])}`.compile()
assert.strictEqual(query, `SELECT * FROM "people" WHERE id IN ($1,$2,$3)`)
assert.deepStrictEqual(params, [1, 2, "x"])
}))
it.effect("and helper", () =>
Effect.gen(function*() {
const sql = yield* PgliteClient.PgliteClient
const now = new Date()
const [query, params] = sql`SELECT * FROM ${sql("people")} WHERE ${
sql.and([sql.in("name", ["Tim", "John"]), sql`created_at < ${now}`])
}`.compile()
assert.strictEqual(query, `SELECT * FROM "people" WHERE ("name" IN ($1,$2) AND created_at < $3)`)
assert.deepStrictEqual(params, ["Tim", "John", now])
}))
it.effect("identifier transform", () =>
Effect.gen(function*() {
const sql = yield* PgliteClient.PgliteClient
const compiler = PgliteClient.makeCompiler((s) => s.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`))
const [query] = compiler.compile(sql`SELECT * FROM ${sql("peopleTest")}`, false)
assert.strictEqual(query, `SELECT * FROM "people_test"`)
}))
it.effect("json fragment", () =>
Effect.gen(function*() {
const sql = yield* PgliteClient.PgliteClient
const rows = yield* sql<{ json: unknown }>`SELECT ${sql.json({ a: 1 })}::jsonb AS json`
assert.deepStrictEqual(rows[0].json, { a: 1 })
}))
it.effect("listen + notify", () =>
Effect.gen(function*() {
const sql = yield* PgliteClient.PgliteClient
const deferred = yield* Deferred.make<string>()
const unsub = yield* Effect.tryPromise({
try: () => sql.pglite.listen("ch1", (payload) => Effect.runFork(Deferred.succeed(deferred, payload))),
catch: (cause) => cause
})
yield* sql.notify("ch1", "hello")
assert.strictEqual(yield* Deferred.await(deferred), "hello")
yield* Effect.promise(() => unsub())
}), { timeout: 15_000 })
it.effect("provider extras", () =>
Effect.gen(function*() {
const sql = yield* PgliteClient.PgliteClient
const dump = yield* sql.dumpDataDir("none")
assert.isAbove((dump as Blob).size, 0)
}))
})
describe("fromClient", () => {
layer(
PgliteClient.layerFrom(Effect.gen(function*() {
const pg = new Pglite.PGlite()
return yield* PgliteClient.fromClient({ liveClient: pg })
})),
{ timeout: "30 seconds" }
)((it) => {
it.effect("works", () =>
Effect.gen(function*() {
const sql = yield* PgliteClient.PgliteClient
const rows = yield* sql<{ value: number }>`SELECT 1 AS value`
assert.deepStrictEqual(rows, [{ value: 1 }])
}))
})
layer(
Layer.effectDiscard(Effect.gen(function*() {
const sql = yield* PgliteClient.PgliteClient
yield* sql`CREATE TYPE mood AS ENUM ('sad', 'happy')`
yield* sql`CREATE TABLE test_moods (id SERIAL PRIMARY KEY, name TEXT, moods mood[])`
yield* sql.refreshArrayTypes
})).pipe(
Layer.provideMerge(ClientLayer)
),
{ timeout: "30 seconds" }
)((it) => {
it.effect("refreshArrayTypes", () =>
Effect.gen(function*() {
const sql = yield* PgliteClient.PgliteClient
yield* sql`INSERT INTO test_moods (name, moods) VALUES (${"test2"}, ${["sad", "happy"]})`
const rows = yield* sql<{ moods: ReadonlyArray<string> }>`SELECT moods FROM test_moods`
assert.deepStrictEqual(rows, [{ moods: ["sad", "happy"] }])
}))
})
})
})

View File

@@ -0,0 +1,45 @@
import { PgliteClient, PgliteMigrator } from "@effect/sql-pglite"
import { assert, describe, layer } from "@effect/vitest"
import { Effect, Layer } from "effect"
import { SqlClient } from "effect/unstable/sql/SqlClient"
const ClientLayer = PgliteClient.layer({})
const loader = Effect.succeed([
[
1,
"init",
Effect.succeed(Effect.gen(function*() {
const sql = yield* SqlClient
yield* sql`CREATE TABLE migrator_test (id SERIAL PRIMARY KEY, value TEXT)`
}))
] as const,
[
2,
"insert",
Effect.succeed(Effect.gen(function*() {
const sql = yield* SqlClient
yield* sql`INSERT INTO migrator_test (value) VALUES ('hello')`
}))
] as const
])
const MigratorLayer = PgliteMigrator.layer({ loader }).pipe(Layer.provide(ClientLayer))
describe("PgliteMigrator", () => {
layer(Layer.merge(ClientLayer, MigratorLayer), { timeout: "30 seconds" })((it) => {
it.effect("runs migrations and records them", () =>
Effect.gen(function*() {
const sql = yield* PgliteClient.PgliteClient
const rows = yield* sql<{ value: string }>`SELECT value FROM migrator_test`
assert.deepStrictEqual(rows, [{ value: "hello" }])
const migrations = yield* sql<
{ migration_id: number; name: string }
>`SELECT migration_id, name FROM effect_sql_migrations ORDER BY migration_id`
assert.deepStrictEqual(
migrations.map((m) => [m.migration_id, m.name]),
[[1, "init"], [2, "insert"]]
)
}))
})
})

View File

@@ -0,0 +1,56 @@
import { PgliteClient } from "@effect/sql-pglite"
import { assert, describe, it } from "@effect/vitest"
import { Effect } from "effect"
import * as Reactivity from "effect/unstable/reactivity/Reactivity"
import type * as SqlError from "effect/unstable/sql/SqlError"
const queryFailureReason = (cause: unknown) =>
Effect.gen(function*() {
const client = yield* PgliteClient.fromClient({
liveClient: makeFailingClient(cause) as any
})
const error = yield* Effect.flip(client`SELECT 1`)
return error.reason
}).pipe(
Effect.scoped,
Effect.provide(Reactivity.layer)
)
const queryFailureReasonTag = (cause: unknown) => Effect.map(queryFailureReason(cause), (reason) => reason._tag)
const assertUniqueViolation = (reason: SqlError.SqlErrorReason, constraint: string) => {
assert.strictEqual(reason._tag, "UniqueViolation")
if (reason._tag === "UniqueViolation") {
assert.strictEqual(reason.constraint, constraint)
}
}
const makeFailingClient = (cause: unknown) => ({
query: () => Promise.reject(cause)
})
describe("PgliteClient SqlError classification", () => {
it.effect("classifies 23505 as UniqueViolation and trims the constraint name", () =>
Effect.gen(function*() {
const reason = yield* queryFailureReason({ code: "23505", constraint: " users_email_key " })
assertUniqueViolation(reason, "users_email_key")
}))
it.effect("uses unknown for missing, non-string, or blank unique violation constraints", () =>
Effect.gen(function*() {
const missing = yield* queryFailureReason({ code: "23505" })
assertUniqueViolation(missing, "unknown")
const nonString = yield* queryFailureReason({ code: "23505", constraint: 123 })
assertUniqueViolation(nonString, "unknown")
const blank = yield* queryFailureReason({ code: "23505", constraint: " " })
assertUniqueViolation(blank, "unknown")
}))
it.effect("keeps non-unique integrity constraints classified as ConstraintError", () =>
Effect.gen(function*() {
const tag = yield* queryFailureReasonTag({ code: "23503", constraint: "orders_user_id_fkey" })
assert.strictEqual(tag, "ConstraintError")
}))
})

View File

@@ -0,0 +1,62 @@
import { PgliteClient } from "@effect/sql-pglite"
import { assert, describe, layer } from "@effect/vitest"
import { Effect } from "effect"
const ClientLayer = PgliteClient.layer({})
const setup = (table: string) =>
Effect.gen(function*() {
const sql = yield* PgliteClient.PgliteClient
yield* sql.unsafe(`CREATE TABLE IF NOT EXISTS ${table} (id SERIAL PRIMARY KEY, name TEXT)`)
yield* sql.unsafe(`TRUNCATE TABLE ${table} RESTART IDENTITY`)
return sql
})
describe("PgliteClient transactions", () => {
layer(ClientLayer, { timeout: "30 seconds" })((it) => {
it.effect("withTransaction commit", () =>
Effect.gen(function*() {
const sql = yield* setup("tx_commit")
yield* sql.withTransaction(sql.unsafe(`INSERT INTO tx_commit (name) VALUES ('hello')`))
const rows = yield* sql.unsafe<{ name: string }>(`SELECT name FROM tx_commit`)
assert.deepStrictEqual(rows, [{ name: "hello" }])
}))
it.effect("withTransaction rollback", () =>
Effect.gen(function*() {
const sql = yield* setup("tx_rollback")
yield* sql.unsafe(`INSERT INTO tx_rollback (name) VALUES ('hello')`).pipe(
Effect.andThen(Effect.fail("boom")),
sql.withTransaction,
Effect.ignore
)
const rows = yield* sql.unsafe(`SELECT * FROM tx_rollback`)
assert.deepStrictEqual(rows, [])
}))
it.effect("nested transaction commits both", () =>
Effect.gen(function*() {
const sql = yield* setup("tx_nested_commit")
const stmt = sql.unsafe(`INSERT INTO tx_nested_commit (name) VALUES ('hello')`)
yield* stmt.pipe(Effect.andThen(() => stmt.pipe(sql.withTransaction)), sql.withTransaction)
const rows = yield* sql.unsafe<{ total: number }>(
`SELECT count(*)::int AS total FROM tx_nested_commit`
)
assert.strictEqual(rows.at(0)?.total, 2)
}))
it.effect("nested transaction rollback via savepoint", () =>
Effect.gen(function*() {
const sql = yield* setup("tx_nested_rollback")
const stmt = sql.unsafe(`INSERT INTO tx_nested_rollback (name) VALUES ('hello')`)
yield* stmt.pipe(
Effect.andThen(() => stmt.pipe(Effect.andThen(Effect.fail("boom")), sql.withTransaction, Effect.ignore)),
sql.withTransaction
)
const rows = yield* sql.unsafe<{ total: number }>(
`SELECT count(*)::int AS total FROM tx_nested_rollback`
)
assert.strictEqual(rows.at(0)?.total, 1)
}))
})
})