Skip to content
Draft
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
50 changes: 25 additions & 25 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ lazy val sql = crossProject(JVMPlatform, JSPlatform, NativePlatform)
.module("sql", "JDBC API wrapped project with Effect System")
.platformsSettings(JSPlatform, NativePlatform)(
libraryDependencies ++= Seq(
"io.github.cquiroz" %%% "scala-java-time" % "2.5.0"
"io.github.cquiroz" %%% "scala-java-time" % "2.6.0"
)
)

Expand All @@ -45,8 +45,8 @@ lazy val core = crossProject(JVMPlatform, JSPlatform, NativePlatform)
.module("core", "Core project for ldbc")
.settings(
libraryDependencies ++= Seq(
"org.typelevel" %%% "cats-free" % "2.10.0",
"org.typelevel" %%% "cats-effect" % "3.6.2"
"org.typelevel" %%% "cats-free" % "2.13.0",
"org.typelevel" %%% "cats-effect" % "3.7.0-RC1"
)
)
.dependsOn(sql)
Expand All @@ -56,9 +56,9 @@ lazy val dsl = crossProject(JVMPlatform, JSPlatform, NativePlatform)
.module("dsl", "Projects that provide a way to connect to the database")
.settings(
libraryDependencies ++= Seq(
"org.typelevel" %%% "twiddles-core" % "0.8.0",
"co.fs2" %%% "fs2-core" % "3.12.0",
"org.typelevel" %%% "munit-cats-effect" % "2.1.0" % Test
"org.typelevel" %%% "twiddles-core" % "0.9.0",
"co.fs2" %%% "fs2-core" % "3.13.0-M7",
"org.typelevel" %%% "munit-cats-effect" % "2.2.0-RC1" % Test
)
)
.dependsOn(core)
Expand Down Expand Up @@ -94,8 +94,8 @@ lazy val codegen = crossProject(JVMPlatform, JSPlatform, NativePlatform)
.module("codegen", "Project to generate code from Sql")
.settings(
libraryDependencies ++= Seq(
"org.scala-lang.modules" %%% "scala-parser-combinators" % "2.3.0",
"org.typelevel" %%% "munit-cats-effect" % "2.1.0" % Test
"org.scala-lang.modules" %%% "scala-parser-combinators" % "2.4.0",
"org.typelevel" %%% "munit-cats-effect" % "2.2.0-RC1" % Test
)
)
.jvmSettings(
Expand All @@ -105,7 +105,7 @@ lazy val codegen = crossProject(JVMPlatform, JSPlatform, NativePlatform)
)
)
.platformsSettings(JSPlatform, NativePlatform)(
libraryDependencies += "com.armanbilge" %%% "circe-scala-yaml" % "0.0.4"
libraryDependencies += "com.armanbilge" %%% "circe-scala-yaml" % "0.0.4-56-02c055c-20251223T140541Z-SNAPSHOT"
)
.dependsOn(schema)

Expand All @@ -125,8 +125,8 @@ lazy val authenticationPlugin = crossProject(JVMPlatform, JSPlatform, NativePlat
.module("authentication-plugin", "MySQL authentication plugin written in pure Scala3")
.settings(
libraryDependencies ++= Seq(
"org.typelevel" %%% "cats-core" % "2.10.0",
"org.scodec" %%% "scodec-bits" % "1.1.38"
"org.typelevel" %%% "cats-core" % "2.12.0",
"org.scodec" %%% "scodec-bits" % "1.2.4"
)
)
.jsSettings(
Expand All @@ -141,14 +141,14 @@ lazy val connector = crossProject(JVMPlatform, JSPlatform, NativePlatform)
.settings(
scalacOptions += "-Ykind-projector:underscores",
libraryDependencies ++= Seq(
"co.fs2" %%% "fs2-core" % "3.12.2",
"co.fs2" %%% "fs2-io" % "3.12.2",
"org.scodec" %%% "scodec-bits" % "1.1.38",
"org.scodec" %%% "scodec-core" % "2.2.2",
"org.scodec" %%% "scodec-cats" % "1.2.0",
"org.typelevel" %%% "otel4s-core-trace" % "0.14.0",
"org.typelevel" %%% "twiddles-core" % "0.8.0",
"org.typelevel" %%% "munit-cats-effect" % "2.1.0" % Test
"co.fs2" %%% "fs2-core" % "3.13.0-M7",
"co.fs2" %%% "fs2-io" % "3.13.0-M7",
"org.scodec" %%% "scodec-bits" % "1.2.4",
"org.scodec" %%% "scodec-core" % "2.3.1",
"org.scodec" %%% "scodec-cats" % "1.3.0-RC1",
"org.typelevel" %%% "otel4s-core-trace" % "0.15.0",
"org.typelevel" %%% "twiddles-core" % "0.9.0",
"org.typelevel" %%% "munit-cats-effect" % "2.2.0-RC1" % Test
)
)
.jsSettings(
Expand All @@ -163,10 +163,10 @@ lazy val awsAuthenticationPlugin = crossProject(JVMPlatform, JSPlatform, NativeP
.module("aws-authentication-plugin", "Project for the plugin used with Aurora IAM authentication")
.settings(
libraryDependencies ++= Seq(
"co.fs2" %%% "fs2-core" % "3.12.2",
"co.fs2" %%% "fs2-io" % "3.12.2",
"io.github.cquiroz" %%% "scala-java-time" % "2.5.0",
"org.typelevel" %%% "munit-cats-effect" % "2.1.0" % Test
"co.fs2" %%% "fs2-core" % "3.13.0-M7",
"co.fs2" %%% "fs2-io" % "3.13.0-M7",
"io.github.cquiroz" %%% "scala-java-time" % "2.6.0",
"org.typelevel" %%% "munit-cats-effect" % "2.2.0-RC1" % Test
)
)
.jsSettings(
Expand Down Expand Up @@ -210,7 +210,7 @@ lazy val tests = crossProject(JVMPlatform, JSPlatform, NativePlatform)
crossScalaVersions := Seq(scala3, scala37),
name := "tests",
description := "Projects for testing",
libraryDependencies += "org.typelevel" %%% "munit-cats-effect" % "2.1.0",
libraryDependencies += "org.typelevel" %%% "munit-cats-effect" % "2.2.0-RC1",
Test / unmanagedSourceDirectories ++= {
val sourceDir = (Test / sourceDirectory).value
CrossVersion.partialVersion(scalaVersion.value) match {
Expand Down Expand Up @@ -290,7 +290,7 @@ lazy val otelExample = crossProject(JVMPlatform)
.example("otel", "OpenTelemetry example project")
.settings(
libraryDependencies ++= Seq(
"org.typelevel" %% "otel4s-oteljava" % "0.14.0",
"org.typelevel" %% "otel4s-oteljava" % "0.15.0",
"io.opentelemetry" % "opentelemetry-exporter-otlp" % "1.57.0" % Runtime,
"io.opentelemetry" % "opentelemetry-sdk-extension-autoconfigure" % "1.57.0" % Runtime
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ trait EncryptPasswordPlugin:
(0 until length).map(pos => (from(pos) ^ scramble(pos % scrambleLength)).toByte).toArray

private def encryptWithRSAPublicKey(input: Array[Byte], publicKey: String): Array[Byte] =
Zone { implicit zone =>
Zone.acquire { implicit zone =>
val publicKeyCStr = toCString(publicKey)
val bio = BIO_new_mem_buf(publicKeyCStr, publicKey.length)
if bio == null then throw new RuntimeException("Failed to create a new memory BIO.")
Expand All @@ -54,17 +54,17 @@ trait EncryptPasswordPlugin:
throw new RuntimeException("Failed to set MGF1 hash function.")
}

val inputBuf = alloc[UByte](input.length.toULong)
val inputBuf = alloc[UByte](input.length)
for i <- input.indices do !(inputBuf + i) = input(i).toUByte

val outLen = stackalloc[CSize]()
!outLen = 0.toULong
!outLen = 0.toCSize

if EVP_PKEY_encrypt(ctx, null, outLen, inputBuf, input.length.toULong) <= 0 then
if EVP_PKEY_encrypt(ctx, null, outLen, inputBuf, input.length.toCSize) <= 0 then
throw new RuntimeException("Failed to obtain the output buffer size required for encryption.")

val encryptedBuf = alloc[UByte](!outLen)
if EVP_PKEY_encrypt(ctx, encryptedBuf, outLen, inputBuf, input.length.toULong) <= 0 then
if EVP_PKEY_encrypt(ctx, encryptedBuf, outLen, inputBuf, input.length.toCSize) <= 0 then
throw new RuntimeException("Encryption failed.")

val result = Array.fill[Byte]((!outLen).toInt)(0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ final case class SimpleHttpClient[F[_]: Network: Async](
override def createSocket(address: SocketAddress[Host], isSecure: Boolean, host: String): Resource[F, Socket[F]] =
if isSecure then
for
socket <- Network[F].client(address)
socket <- Network[F].connect(address)
tlsContext <- Network[F].tlsContext.systemResource
tlsSocket <- tlsContext
.clientBuilder(socket)
.withParameters(TLSParameters(servername = Some(host)))
.build
yield tlsSocket
else Network[F].client(address)
else Network[F].connect(address)
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ final case class SimpleHttpClient[F[_]: Network: Async](
override def createSocket(address: SocketAddress[Host], isSecure: Boolean, host: String): Resource[F, Socket[F]] =
if isSecure then
for
socket <- Network[F].client(address)
socket <- Network[F].connect(address)
tlsContext <- Network[F].tlsContext.systemResource
tlsSocket <- tlsContext
.clientBuilder(socket)
.withParameters(TLSParameters(serverNames = Some(List(new SNIHostName(host)))))
.build
yield tlsSocket
else Network[F].client(address)
else Network[F].connect(address)
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ final case class SimpleHttpClient[F[_]: Network: Async](
override def createSocket(address: SocketAddress[Host], isSecure: Boolean, host: String): Resource[F, Socket[F]] =
if isSecure then
for
socket <- Network[F].client(address)
socket <- Network[F].connect(address)
tlsContext <- Network[F].tlsContext.systemResource
tlsSocket <- tlsContext
.clientBuilder(socket)
.withParameters(TLSParameters(serverName = Some(host)))
.build
yield tlsSocket
else Network[F].client(address)
else Network[F].connect(address)
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

package ldbc.connector

import java.nio.file.Path
import java.nio.file.Path as JPath
import java.security.KeyStore

import javax.net.ssl.SSLContext
Expand All @@ -15,6 +15,7 @@ import cats.*

import cats.effect.Resource

import fs2.io.file.Path
import fs2.io.net.tls.TLSContext
import fs2.io.net.Network

Expand All @@ -26,6 +27,19 @@ private[ldbc] trait SSLPlatform:
override def tlsContext[F[_]: Network](implicit ev: ApplicativeError[F, Throwable]): Resource[F, TLSContext[F]] =
Resource.pure(Network[F].tlsContext.fromSSLContext(ctx))

/** Creates an `SSL` from the specified key store file. */
@deprecated("Use overload that takes an fs2.io.file.Path instead", "0.X.0")
def fromKeyStoreFile(
file: JPath,
storePassword: Array[Char],
keyPassword: Array[Char]
): SSL =
new SSL:
override def tlsContext[F[_]: Network](implicit ev: ApplicativeError[F, Throwable]): Resource[F, TLSContext[F]] =
Resource.eval(
Network[F].tlsContext.fromKeyStoreFile(fs2.io.file.Path.fromNioPath(file), storePassword, keyPassword)
)

/** Creates an `SSL` from the specified key store file. */
def fromKeyStoreFile(
file: Path,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ object Connection:

for
sslOp <- ssl.toSSLNegotiationOptions(if debug then logger.some else none)
connection <- fromSocketGroup(
connection <- fromNetwork(
Network[F],
host,
port,
Expand Down Expand Up @@ -246,6 +246,58 @@ object Connection:
_ <- Resource.make(acquire(connection))(v => release(v, connection))
yield connection

def fromNetwork[F[_]: Tracer: Console: Hashing: UUIDGen, A](
network: Network[F],
host: String,
port: Int,
user: String,
password: Option[String] = None,
database: Option[String] = None,
debug: Boolean = false,
socketOptions: List[SocketOption],
sslOptions: Option[SSLNegotiation.Options[F]],
readTimeout: Duration = Duration.Inf,
allowPublicKeyRetrieval: Boolean = false,
useCursorFetch: Boolean = false,
useServerPrepStmts: Boolean = false,
databaseTerm: Option[DatabaseMetaData.DatabaseTerm] = None,
defaultAuthenticationPlugin: Option[AuthenticationPlugin[F]],
plugins: List[AuthenticationPlugin[F]],
acquire: Connection[F] => F[A],
release: (A, Connection[F]) => F[Unit]
)(using ev: Async[F]): Resource[F, LdbcConnection[F]] =

def fail[B](msg: String): Resource[F, B] =
Resource.eval(ev.raiseError(new SQLClientInfoException(msg)))

def sockets: Resource[F, Socket[F]] =
(Hostname.fromString(host), Port.fromInt(port)) match
case (Some(validHost), Some(validPort)) =>
network.connect(SocketAddress(validHost, validPort), socketOptions)
case (None, _) => fail(s"""Hostname: "$host" is not syntactically valid.""")
case (_, None) => fail(s"Port: $port falls out of the allowed range.")

fromSockets(
sockets,
host,
port,
user,
password,
database,
debug,
sslOptions,
readTimeout,
allowPublicKeyRetrieval,
useCursorFetch,
useServerPrepStmts,
databaseTerm,
defaultAuthenticationPlugin,
plugins,
acquire,
release
)

@deprecated("0.X.0", "Use fromNetwork instead")
def fromSocketGroup[F[_]: Tracer: Console: Hashing: UUIDGen, A](
socketGroup: SocketGroup[F],
host: String,
Expand Down
2 changes: 1 addition & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ addSbtPlugin("pl.project13.scala" % "sbt-jmh"
addSbtPlugin("org.typelevel" % "sbt-typelevel" % "0.8.3")
addSbtPlugin("org.typelevel" % "sbt-typelevel-site" % "0.8.3")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.20.1")
addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.4.17")
addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.9")
addSbtPlugin("com.armanbilge" % "sbt-scala-native-config-brew-github-actions" % "0.4.0")
addSbtPlugin("com.github.sbt" % "sbt-boilerplate" % "0.8.0")
addSbtPlugin("io.chrisdavenport" %% "sbt-npm-package" % "0.2.0")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,6 @@ trait ConnectionPoolDslTest extends CatsEffectSuite:
.fromConfig[IO](config.setMinConnections(2).setMaxConnections(5))
.use { pool =>
// Execute multiple queries concurrently
// TODO: Scala Native 0.5.x will support multi-threading, so we will verify again at that time.
// See: https://github.com/takapi327/ldbc/issues/536
val queries = (1 to 5).toList.parTraverse { i =>
country.selectAll
.limit(1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ trait ConnectionPoolDslTest extends CatsEffectSuite:
.fromConfig[IO](config.setMinConnections(2).setMaxConnections(5))
.use { pool =>
// Execute multiple queries concurrently
val queries = (1 to 5).toList.traverse { i =>
val queries = (1 to 5).toList.parTraverse { i =>
country.selectAll
.limit(1)
.offset(i)
Expand Down
Loading