Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/effect-4-0-6.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@maple-dev/effect-orm": minor
---

Require Effect 4.0.6 (`effect ^4.0.6` peer). Effect now fails a transaction whose COMMIT failed
with a `SqlError` instead of dying; `transaction` still reports it as `TransactionCommitFailed`.
`ClickhouseHttpClient` names its driver `"clickhouse-http"` (`SqlClient.driver`), and Effect's own
statement span is now named after the database (`db.namespace`) rather than `sql.execute`.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ Built on [Effect](https://effect.website) (peer dependency).
Install the package with its Effect 4 peer:

```bash
bun add @maple-dev/effect-orm "effect@^4.0.0"
bun add @maple-dev/effect-orm "effect@^4.0.6"
```

See [Getting started](./docs/getting-started.md) for source builds and examples.

`effect` is a peer dependency. The recommended range `^4.0.0` allows
`effect` is a peer dependency. The recommended range `^4.0.6` allows
newer Effect 4 releases without opting into Effect 5. Effect 3 and the Effect 4
prereleases are incompatible.

Expand Down
42 changes: 24 additions & 18 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions design/transactions.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,10 @@ This is a translation of Effect 4.0.0 behavior. The right fix is upstream: COMMI
that is part of phase 2; when it lands, steps 1 and 2 become a no-op. Decided: ship the
translation and file upstream in parallel, not one after the other.

Update (effect 4.0.6): COMMIT failure now arrives as a `SqlError` in the error channel (still a
die when the cleanup after it fails too). Step 2 also accepts that failure when the body
succeeded. ROLLBACK still dies and still replaces the body's exit.

**Retry.** `Database.retryContention(effect, options?)` re-runs `effect` when it fails with
`DatabaseError` or `TransactionCommitFailed` whose reason is `SerializationError` or
`DeadlockError`, three times with exponential backoff from 50 ms by default, matching
Expand Down
8 changes: 4 additions & 4 deletions docs/database.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
connections: a `Database` is a small object over your client.

```sh
npm install @effect/sql-pg@4.0.0 # or @effect/sql-pglite, @effect/sql-clickhouse
npm install @effect/sql-pg@4.0.6 # or @effect/sql-pglite, @effect/sql-clickhouse
```

Transactions are Effect's own `SqlClient.withTransaction`, with four additions:

- **Settings**: isolation level, access mode, deferrable.
- **Typed COMMIT and ROLLBACK failures**: Effect 4.0.0 turns them into defects.
- **Typed COMMIT and ROLLBACK failures**: Effect fails with a bare `SqlError` or dies.
- **A guard** against statements that outlive their transaction.
- **Contention retry** for SQLSTATE 40001 and 40P01.

Expand Down Expand Up @@ -220,8 +220,8 @@ again. `read uncommitted` is not offered because Postgres runs it as `read commi
| `TransactionOptionsRejected` | A setting the dialect does not support, or settings on a nested transaction |
| `TransactionUnsupported` | The dialect has no transactions (ClickHouse) |

Effect 4.0.0 turns a failed COMMIT or ROLLBACK into a defect and, when ROLLBACK fails, drops
the body's own failure. `transaction` turns both back into the typed errors above. Defects
Effect fails with a bare `SqlError` on a failed COMMIT, dies on a failed ROLLBACK and, when
ROLLBACK fails, drops the body's own failure. `transaction` turns these into the typed errors above. Defects
from `body` stay defects.

`TransactionClosed` is a defect, not an error to handle. A fiber forked inside a transaction
Expand Down
8 changes: 4 additions & 4 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ Effect application: `Effect.runPromise` lets you use it from ordinary async code
CommonJS code can `require()` every entry point too, on Node 20.19+ or 22.12+, which
load ES modules synchronously (`require(esm)`). That is the same way such code loads Effect 4,
which is also ESM-only, so the library and its caller share one Effect.
These examples are checked against Effect `4.0.0` and the builder in this repository.
The package declares `effect ^4.0.0` as a peer dependency; Effect 3 is incompatible.
These examples are checked against Effect `4.0.6` and the builder in this repository.
The package declares `effect ^4.0.6` as a peer dependency; Effect 3 is incompatible.

Install from npm with its Effect 4 peer dependency:

```sh
npm install @maple-dev/effect-orm "effect@^4.0.0"
npm install @maple-dev/effect-orm "effect@^4.0.6"
```

The recommended range accepts stable Effect 4 releases. It excludes Effect 3, the
Expand All @@ -36,7 +36,7 @@ bun pm pack
Install the resulting `.tgz` into your own project with its peer dependency:

```sh
npm install /absolute/path/to/the-generated-package.tgz "effect@^4.0.0"
npm install /absolute/path/to/the-generated-package.tgz "effect@^4.0.6"
```

Keep the Effect 4 range explicit when installing. Use an ESM project
Expand Down
4 changes: 2 additions & 2 deletions docs/running-queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ column types already assume.
## A complete client example

For Node.js or Bun, install Effect's ClickHouse client separately. Use the same Effect 4
release as your `effect` dependency; this example is checked against `4.0.0`:
release as your `effect` dependency; this example is checked against `4.0.6`:

```sh
npm install effect@4.0.0 @effect/sql-clickhouse@4.0.0
npm install effect@4.0.6 @effect/sql-clickhouse@4.0.6
```

This example reads five rows from ClickHouse's built-in `system.numbers` table, declared
Expand Down
18 changes: 9 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,15 @@
"@changesets/cli": "3.0.3",
"@clickhouse/client": "1.21.0",
"@effect/language-service": "^0.87.3",
"@effect/platform-bun": "4.0.0",
"@effect/sql-clickhouse": "4.0.0",
"@effect/sql-d1": "4.0.0",
"@effect/sql-pglite": "4.0.0",
"@effect/sql-sqlite-node": "4.0.0",
"@effect/vitest": "4.0.0",
"@effect/platform-bun": "4.0.6",
"@effect/sql-clickhouse": "4.0.6",
"@effect/sql-d1": "4.0.6",
"@effect/sql-pglite": "4.0.6",
"@effect/sql-sqlite-node": "4.0.6",
"@effect/vitest": "4.0.6",
"@electric-sql/pglite": "0.5.8",
"@types/node": "^22.10.2",
"effect": "4.0.0",
"effect": "4.0.6",
"expect-type": "^1.3.0",
"fast-check": "^4.9.0",
"miniflare": "4.20260730.0",
Expand All @@ -143,10 +143,10 @@
"vitest": "^4.1.9"
},
"peerDependencies": {
"effect": "^4.0.0"
"effect": "^4.0.6"
},
"packageManager": "bun@1.4.0",
"patchedDependencies": {
"@effect/vitest@4.0.0": "patches/@effect%2Fvitest@4.0.0.patch"
"@effect/vitest@4.0.6": "patches/@effect%2Fvitest@4.0.6.patch"
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
diff --git a/dist/internal/internal.js b/dist/internal/internal.js
index 7138319..0fdd563 100644
index ba15b512471edc067d9cb27ed7838ab42bba6c44..8e80dd30505e6414a4bd130cd17a72f87184c27f 100644
--- a/dist/internal/internal.js
+++ b/dist/internal/internal.js
@@ -13,7 +13,8 @@ import * as Scope from "effect/Scope";
@@ -14,7 +14,8 @@ import * as Scope from "effect/Scope";
import * as TestClock from "effect/testing/TestClock";
import * as TestConsole from "effect/testing/TestConsole";
import * as V from "vitest";
Expand All @@ -12,21 +12,21 @@ index 7138319..0fdd563 100644
const runPromise = /*#__PURE__*/Effect.fnUntraced(function* (effect, _ctx) {
const exit = yield* Effect.exit(effect);
if (Exit.isFailure(exit)) {
@@ -29,7 +30,8 @@ const runPromise = /*#__PURE__*/Effect.fnUntraced(function* (effect, _ctx) {
@@ -44,7 +45,8 @@ const settleOnAbort = (ctx, promise) => {
/** @internal */
const runTest = ctx => effect => {
const promise = runPromise(effect, ctx);
- if (ctx) {
- return ctx ? settleOnAbort(ctx, promise) : promise;
+ // Patched (maple): Bun's `bun test` context has no `signal`.
+ if (ctx?.signal) {
// Vitest stops awaiting the test promise once the signal aborts (timeout or
// cancellation), so only then add a hook that waits for the finalizers.
// Registering it unconditionally would change the teardown of every test.
+ return ctx?.signal ? settleOnAbort(ctx, promise) : promise;
};
const TestEnv = /*#__PURE__*/Layer.mergeAll(TestConsole.layer, /*#__PURE__*/TestClock.layer());
/** @internal */
diff --git a/src/internal/internal.ts b/src/internal/internal.ts
index b43385b..e3974e6 100644
index 356c99ebf8d15603ce67bbfd05c05735bf43cd4b..e647e98bdbd8d88ff9ef96d36bfad657e3cb54db 100644
--- a/src/internal/internal.ts
+++ b/src/internal/internal.ts
@@ -17,7 +17,8 @@ import * as TestConsole from "effect/testing/TestConsole"
@@ -18,7 +18,8 @@ import * as TestConsole from "effect/testing/TestConsole"
import * as V from "vitest"
import type * as Vitest from "../index.ts"

Expand All @@ -36,13 +36,13 @@ index b43385b..e3974e6 100644

const runPromise: <E, A>(
_: Effect.Effect<A, E, never>,
@@ -39,7 +40,8 @@ const runPromise: <E, A>(
@@ -53,7 +54,8 @@ const settleOnAbort = <A>(ctx: Vitest.TestContext, promise: Promise<A>) => {
/** @internal */
const runTest = (ctx?: Vitest.TestContext) => <E, A>(effect: Effect.Effect<A, E>) => {
const promise = runPromise(effect, ctx)
- if (ctx) {
- return ctx ? settleOnAbort(ctx, promise) : promise
+ // Patched (maple): Bun's `bun test` context has no `signal`.
+ if (ctx?.signal) {
// Vitest stops awaiting the test promise once the signal aborts (timeout or
// cancellation), so only then add a hook that waits for the finalizers.
// Registering it unconditionally would change the teardown of every test.
+ return ctx?.signal ? settleOnAbort(ctx, promise) : promise
}

/** @internal */
5 changes: 3 additions & 2 deletions src/clickhouse-http/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,13 +259,14 @@ describe("ClickhouseHttpClient", () => {
return Effect.gen(function* () {
const sql = yield* SqlClient.SqlClient
yield* sql.unsafe("SELECT 1")
const span = spans.find((s) => s.name === "sql.execute")
const span = spans.find((s) => s.attributes.has("effect.sql.method"))
assert(span !== undefined)
return Object.fromEntries(span.attributes)
return { name: span.name, ...Object.fromEntries(span.attributes) }
}).pipe(Effect.provide(live), Effect.withTracer(recording))
}
return Effect.gen(function* () {
expect(yield* run({})).toMatchObject({
name: "analytics",
"db.system.name": "clickhouse",
"db.namespace": "analytics",
"server.address": "clickhouse.example",
Expand Down
1 change: 1 addition & 0 deletions src/clickhouse-http/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ export const make = (

const client = yield* Client.make({
acquirer: Effect.succeed(connection),
driver: "clickhouse-http",
compiler,
// The peer, for service maps: with the HTTP span off, nothing else names it.
// The caller's attributes come last, so they can rename the peer.
Expand Down
Loading
Loading