r/scala 4h ago

Cats-Actors 2.2.0 is released

22 Upvotes

Cats-Actors is a Cats Effect native actor library: typed messages, functional state, supervision, and the familiar ! operator, all in F[_].

What is new in this release:

- ControlledTestKit, a new trait in the cats-actors-testkit module. It

provisions an ActorSystem[IO] inside Cats Effect's TestControl and ticks the

simulated clock for you, so scheduled work and timeouts resolve without real

waiting. A one hour receive timeout is now an ordinary unit test that finishes

in milliseconds.

- Receive timeouts, the supervisor restart window and the dead letter mailbox

idle check now read Clock[F].monotonic instead of System.currentTimeMillis, so

they all honour simulated time.

- New TestKit assertions, expectMsgTypeCountN and expectMsgTypeSingle, which

count messages of a type and do not depend on when they arrive relative to

the call.

- Breaking: ActorSystem.uptime is now F[Long] rather than Long.

Scala 2.13 and 3, on JVM, Scala.js and Scala Native.

```

resolvers += "jitpack" at "https://jitpack.io"

libraryDependencies += "com.github.cloudmark.cats-actors" %%% "cats-actors" % "2.2.0"

libraryDependencies += "com.github.cloudmark.cats-actors" %%% "cats-actors-testkit" % "2.2.0" % Test

```

Write up: https://cloudmark.github.io/Cats-Actors-Controlling-Time/

Repo: https://github.com/cloudmark/cats-actors

Feedback and issues welcome.


r/scala 16h ago

Released windymelt/inertia-scala: Inertia.js binding for Scala 3 server

Thumbnail github.com
16 Upvotes

r/scala 10h ago

ldbc v0.8.0 is out 🎉

6 Upvotes

ldbc v0.8.0 released — SQL injection fix under NO_BACKSLASH_ESCAPES, JDBC 4.3 enquote APIs, and sbt 2 support!

TL;DR: Pure Scala MySQL connector running on JVM, Scala.js, and Scala Native fixes a SQL injection in client-side prepared statements under the NO_BACKSLASH_ESCAPES sql_mode, adds the JDBC 4.3 enquote APIs, and cross-builds its codegen plugin for sbt 1 and sbt 2. Upgrading is recommended if you use the ldbc connector.

ldbc v0.8.0 is out. This is primarily a security release for our Pure Scala MySQL connector that works across JVM, Scala.js, and Scala Native platforms.

The headline of this release is a SQL injection fix for sessions running with NO_BACKSLASH_ESCAPES, alongside JDBC 4.3 enquote APIs and sbt 2 support for ldbc-plugin.

https://github.com/takapi327/ldbc/releases/tag/v0.8.0

Major Changes

🔒 SQL Injection under NO_BACKSLASH_ESCAPES

In 0.7.x and earlier, client-side prepared statements escaped string parameters with backslash escaping only ('\') and never consulted the server sql_mode.

In a session running with NO_BACKSLASH_ESCAPES, a backslash is an ordinary character. \' therefore does not neutralize the quote, and a string parameter can break out of its literal.

// 0.7.x and earlier, in a session with sql_mode = 'NO_BACKSLASH_ESCAPES'
ps.setString(1, "zzz' OR 1=1 -- ")
// Rendered SQL: WHERE t.name = 'zzz\' OR 1=1 -- '
//            => (name = 'zzz\') OR 1=1  ... always true

Who is affected: the ldbc connector with useServerPrepStmts = false (the default), against a server or session with NO_BACKSLASH_ESCAPES enabled. The jdbc connector is not affected.

The fix has three parts:

  • All escaping centralised in QueryRendererParameter no longer exposes a SQL-text representation for strings, so a path that bypasses the sql_mode-aware logic cannot exist by construction
  • Escaping follows the sql_mode — quote-doubling (''') when NO_BACKSLASH_ESCAPES is active, which is the only way to embed a quote such that it can never be consumed by a preceding backslash
  • The sql_mode is tracked for the life of the session — seeded from the handshake status flags and updated from every OK/EOF packet, so a SET SESSION sql_mode = ... issued after connecting is picked up too

No user code changes are required.

🛡️ JDBC 4.3 enquote APIs

Following MySQL Connector/J 9.7.0 (WL #17215), four methods have been added to ldbc.sql.Statement for safely quoting values and identifiers when you assemble SQL as a string.

for
  stmt <- conn.createStatement()
  a    <- stmt.enquoteLiteral("G'Day")              // 'G''Day'
  b    <- stmt.enquoteIdentifier("my table", false) // `my table`
  c    <- stmt.enquoteIdentifier("user", true)      // `user`
  d    <- stmt.enquoteNCharLiteral("Hello")         // N'Hello'
  e    <- stmt.isSimpleIdentifier("user_name")      // true
  f    <- stmt.isSimpleIdentifier("select")         // false (reserved word)
yield ()

isSimpleIdentifier follows the MySQL rules: [0-9a-zA-Z$_] or extended characters (U+0080 and above), not all digits, at most 64 characters, and not a reserved word. When ANSI_QUOTES is enabled, the identifier quote character becomes " instead of \`.

Available on both Statement and PreparedStatement, for the ldbc connector as well as the jdbc connector. The existing ident() helper remains the right tool inside the sql interpolator.

🔧 sbt 2 Support for ldbc-plugin

ldbc-plugin is now cross-built for both sbt 1 and sbt 2 — artifacts for sbt 1 (Scala 2.12) and sbt 2 (Scala 3) are published side by side. The declaration is identical either way; sbt resolves the right artifact.

// project/plugins.sbt — the same for sbt 1.x and sbt 2.x
addSbtPlugin("io.github.takapi327" % "ldbc-plugin" % "0.8.0")

This was the goal set out for the 0.8.x series. Note that the ldbc build itself still runs on sbt 1, because sbt-typelevel has not been published for sbt 2 yet.

🪲 insert Column-Order Fix

The tuple overload of insert now goes through the entity mapping defined by the table's * projection.

userTable.insert((1L, "Alice", Some(20)))

Previously the tuple was cast onto the column encoder directly, so values could be inserted into the wrong columns whenever the field order of the model differed from the column order of the * projection. The change makes the result correct, but if you have such a table it is worth re-running your tests after upgrading.

📦 Dependency Updates

Library Before (0.7.x) After (0.8.0)
MySQL Connector/J 9.6.0 9.7.0
twiddles-core 0.10.0 1.1.0

⚠️ Breaking Changes

Parameter is now sealed and no longer exposes sql

ldbc.connector.data.Parameter is now a sealed trait with one case class per type, and def sql: String has been removed. This is part of the SQL injection fix — rendering a string into a SQL literal depends on the sql_mode, so that representation was removed to leave QueryRenderer as the only route.

Custom Parameter implementations are no longer possible; use the factory methods such as Parameter.string(...). Code that read param.sql should use param.toString, which is a sql_mode-independent literal for display and diagnostics only — it must not be used to assemble SQL for execution.

params removed from SQLException

SQLException and its subclasses lost the params: SortedMap[Int, Parameter] argument, as did ERRPacket.toException. As a result, the OpenTelemetry attributes error.parameter.$i.type / error.parameter.$i.value and the "and the arguments were" section of exception messages are no longer emitted.

This closes the paths by which bound values could leak through exception messages and telemetry. If you build dashboards or alerts on those attributes, you are affected.

Four abstract methods added to Statement

The four enquote methods are abstract members of ldbc.sql.Statement. No impact if you use the connectors ldbc provides, but implementing Statement or PreparedStatement yourself will now fail to compile.

What has not changed

0.7.x 0.8.0
Java versions 17, 21, 25
Scala versions 3.3.x / 3.8.x

Deprecated APIs

The APIs deprecated in 0.7.0 remain available in 0.8.0 and will be removed in a future release.

API Replacement
sc(identifier) ident(identifier)
Connection.fromSocketGroup(...) Connection.fromNetwork(...)
SSL.fromKeyStoreFile(java.nio.file.Path, ...) SSL.fromKeyStoreFile(fs2.io.file.Path, ...)

Why ldbc?

  • 100% Pure Scala — No JDBC dependency required
  • True cross-platform — Single codebase for JVM, JS, and Native
  • Fiber-native design — Built from the ground up for Cats Effect
  • ZIO Integration — Complete ZIO ecosystem support
  • First-class testability — Dedicated rollback and MUnit testing modules
  • Production-ready observability — OpenTelemetry Semantic Conventions compliant
  • Enterprise-ready — AWS Aurora IAM authentication support
  • AI/ML ready — MySQL VECTOR type support
  • Security-focused — sql_mode-aware parameter escaping and JDBC 4.3 enquote APIs
  • sbt 1 & sbt 2 — Codegen plugin cross-built for both
  • Migration-friendly — Easy upgrade path from 0.7.x

Links


r/scala 18h ago

Code generation from OpenAPI specs

3 Upvotes

Quick question, how the heck you guys generate Scala code from OpenAPI specs?

I have been trying to generate client code for Meta business API using the Scala generators from openapi-generator but there is always a problem:

All of them, ignore the oneOf spec on openapi (that in theory should generate a sealed trait as the sum type implementation) and instead they generate a single case class with all fields required, nothing is optional.

What is the tool/strategy you guys use to generate API model from OpenAPI? At this point, i'm considering to generate the Scala code using an LLM instead of the classic deterministic approach.

Thanks 🙏