Skip to content

#52: Use type classe for AllowedParamTypes#58

Merged
benedeki merged 4 commits intomasterfrom
feature/52-use-type-classe-for-allowedparamtypes
Nov 27, 2025
Merged

#52: Use type classe for AllowedParamTypes#58
benedeki merged 4 commits intomasterfrom
feature/52-use-type-classe-for-allowedparamtypes

Conversation

@benedeki
Copy link
Contributor

@benedeki benedeki commented Nov 26, 2025

  • AllowedParamTypes renamed to QueryParamType and changed to typeclass
  • SetterFnc renamed and refactored into QueryParamValue
  • Moved Postgres specific stuff into its own package
  • Dropped deprecated JsonBString class and support
  • Deprecated addNull functions instead implemented a constant QueryParamValue.NULL
  • Dependency on Postgres made optional
  • Added scalac options to project
  • Incremented sbt version
  • Enhanced .gitignore to better cover VS Code files

Closes #52

Summary by CodeRabbit

  • New Features

    • DBConnection can be created from URL/credentials and used as a JDBC Connection implicitly.
    • Postgres-specific SimpleJsonString support added.
  • Deprecations / Breaking

    • Older NULL helper methods deprecated—use explicit NULL parameter values.
    • Deprecated JsonB alias removed.
  • Chores / Refactor

    • Parameter handling refactored to a typeclass/value model (affects how NULLs are passed).
    • .gitignore, compiler warnings, sbt version, dependency config, and CI release-notes check updated.

✏️ Tip: You can customize this high-level summary in your review settings.

Release notes:

  • The parameter of queries are now entered using type-classes instead of a limited list of suported types. This make it extensibel in a standard Scala-idiomatic way.
  • Introduced NULL constant for parameters.
  • Better organization of the code.

* `AllowedParamTypes` renamed to `QueryParamType` and changed to typeclass
* `SetterFnc` renamed and refactored into `QueryParamValue`
* Moved Postgres specific stuff into its own package
* Dropped deprecated `JsonBString` class and support
* Deprecated `addNull` functions instead implemented a constant `QueryParamValue.NULL`
* Dependency on Postgres made optional
* Added scalas options to project
* Incremented sbt version
* Enhanced `.gitignore` to better cover VS Code files
@benedeki benedeki self-assigned this Nov 26, 2025
@benedeki benedeki added the breaking change Introduces change, that is incompatible with last release label Nov 26, 2025
@github-actions
Copy link

github-actions bot commented Nov 26, 2025

JaCoCo 'balta' module code coverage report - scala 2.12.18

Overall Project 67.11% -14.43% 🍏
Files changed 48.81% 🍏

File Coverage
ConnectionInfo.scala 100% 🍏
DBQuerySupport.scala 100% 🍏
DBTable.scala 91.28% -3% 🍏
DBFunction.scala 60.68% -15.53% 🍏
QueryParamValue.scala 59.72% -48.61% 🍏
DBConnection.scala 55.81% -27.91% 🍏
SimpleJsonString.scala 50% -57.69% 🍏
Params.scala 49.34% -36.18% 🍏
QueryParamType.scala 28.3% -71.7% 🍏
DBTestSuite.scala 24.2% 🍏
Postgres.scala 15.22% 🍏
PostgresQueryParamValue.scala 0% 🍏

@coderabbitai
Copy link

coderabbitai bot commented Nov 26, 2025

Walkthrough

Replaces the SetterFnc/AllowedParamTypes system with QueryParamType/QueryParamValue typeclasses, moves several classes into an inner package, removes deprecated/old setter types, adds PostgreSQL-specific QueryParamValue, updates call sites and tests, and adjusts build/project metadata and .gitignore entries.

Changes

Cohort / File(s) Summary
Typeclass Infrastructure
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamType.scala, balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamValue.scala, balta/src/main/scala/za/co/absa/db/balta/postgres/typeclasses/PostgresQueryParamValue.scala
Added QueryParamType[T] trait with many implicit instances and NULL; added QueryParamValue trait with Object/Simple/Null implementations; added Postgres-specific PostgresObjectQueryParamValue.
Parameter API & Containers
balta/src/main/scala/za/co/absa/db/balta/classes/inner/Params.scala, balta/src/main/scala/za/co/absa/db/balta/DBTestSuite.scala
Reworked Params/NamedParams/OrderedParams to store QueryParamValue; constructors now use QueryParamType conversions; deprecated old NULL helpers and updated helper imports.
Query & Table Handling
balta/src/main/scala/za/co/absa/db/balta/classes/DBFunction.scala, balta/src/main/scala/za/co/absa/db/balta/classes/DBQuerySupport.scala, balta/src/main/scala/za/co/absa/db/balta/classes/DBTable.scala
Replaced SetterFnc lists with QueryParamValue lists across DBFunction, DBQuerySupport and DBTable; updated signatures, parameter binding, WHERE/SQL construction and NULL handling; added deprecation annotations delegating to NULL.
Removed Setter-based Types
balta/src/main/scala/za/co/absa/db/balta/classes/setter/AllowedParamTypes.scala, .../SetterFnc.scala, .../CustomDBType.scala, balta/src/main/scala/za/co/absa/db/balta/classes/simple/JsonBString.scala
Deleted AllowedParamTypes, SetterFnc, CustomDBType and deprecated JsonBString files removing the old setter factory and related types.
Package Reorganization & Moves
balta/src/main/scala/za/co/absa/db/balta/classes/inner/ConnectionInfo.scala, balta/src/main/scala/za/co/absa/db/balta/postgres/classes/SimpleJsonString.scala, tests...
Moved ConnectionInfo and parameter containers into classes.inner; moved SimpleJsonString to postgres.classes and added its QueryParamType instance; updated imports across code and tests.
DBConnection & Implicits
balta/src/main/scala/za/co/absa/db/balta/classes/DBConnection.scala, balta/src/main/scala/za/co/absa/db/balta/implicits/package.scala
Added DBConnection.apply overload accepting raw connection params and added an implicit conversion in DBConnection companion; removed the previous package-object implicit conversion (relocated).
Postgres Implicits
balta/src/main/scala/za/co/absa/db/balta/postgres/implicits/Postgres.scala
Updated Postgres implicits to use new SimpleJsonString location, removed deprecated getJsonB helpers.
Build & Project Files
build.sbt, project/Dependencies.scala, project/build.properties, .gitignore
Enabled scalac warnings -deprecation and -feature; made PostgreSQL JDBC dependency optional; bumped sbt to 1.11.7; added .metals/, .bloop/, metals.sbt to .gitignore.
Tests
balta/src/test/scala/...
Updated imports and usages to pass NULL via add(..., NULL) and to reference moved packages; adjusted tests to new param/value semantics.

Sequence Diagram(s)

sequenceDiagram
  participant Caller as Caller (DBTable/DBFunction/Params)
  participant QType as QueryParamType[T]
  participant QValue as QueryParamValue
  participant Prep as PreparedStatement

  Caller->>QType: implicitly[QueryParamType[T]].toQueryParamValue(value)
  Note right of QType `#eef3ff`: produces QueryParamValue (Object/Simple/Null)
  QType-->>QValue: QueryParamValue
  Caller->>Caller: collect List[QueryParamValue]
  Caller->>Prep: prepareStatement(sql)
  loop bind params
    Caller->>QValue: queryValue.assign.foreach(f => f(prep, idx))
    alt assign present
      Note right of Prep `#e6fff2`: binds parameter at idx
    else no assign (NULL)
      Note right of Prep `#fff7e6`: sqlEntry = "NULL", no bind
    end
  end
  Caller->>Prep: executeQuery / executeUpdate
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Focus review on DBTable.scala and DBQuerySupport.scala (SQL construction and parameter binding semantics).
  • Verify QueryParamType implicit instances and NULL handling across call sites.
  • Check package moves for stale imports and visibility issues.
  • Inspect Postgres PGobject binding (resource correctness) in PostgresQueryParamValue.

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • salamonpavel
  • miroslavpojer
  • lsulak

Poem

🐰 I hopped from SetterFnc to QueryType,
I wrapped each value — object, simple, or NULL.
Postgres PGobjects found their nest,
Params moved inward, imports dressed.
Hop, code, hop — a tidy burrow full!

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly references issue #52 and accurately describes the main change: converting AllowedParamTypes to use type classes instead of a trait-based approach.
Linked Issues check ✅ Passed The PR fully implements the objective from issue #52 by converting AllowedParamTypes into a QueryParamType typeclass, replacing SetterFnc with QueryParamValue, and successfully increasing extensibility through the type class mechanism.
Out of Scope Changes check ✅ Passed The PR includes additional changes beyond the core typeclass conversion (JsonBString removal, Postgres packaging, sbt version update, gitignore updates), which are organizing changes that support the main objective of increasing extensibility.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/52-use-type-classe-for-allowedparamtypes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
balta/src/main/scala/za/co/absa/db/balta/classes/inner/ConnectionInfo.scala (1)

19-27: Incorrect doc comment for ConnectionInfo.

The doc comment describes "a function that sets a parameter of a prepared statement," which does not match the ConnectionInfo case class below. This appears to be a stale comment from a previous or different class.

-/**
- * This is a function that sets a parameter of a prepared statement.
- *
- * @param dbUrl       - the JDBC URL of the database
- * @param username    - the username to use when connecting to the database
- * @param password    - the password to use when connecting to the database
- * @param persistData - whether to persist the data to the database (usually false for tests, set to true for
- *                    debugging purposes)
- */
+/**
+ * Connection information for establishing a database connection.
+ *
+ * @param dbUrl       - the JDBC URL of the database
+ * @param username    - the username to use when connecting to the database
+ * @param password    - the password to use when connecting to the database
+ * @param persistData - whether to persist the data to the database (usually false for tests, set to true for
+ *                    debugging purposes)
+ */
🧹 Nitpick comments (11)
balta/src/test/scala/za/co/absa/db/balta/classes/DBTableIntegrationTests.scala (1)

54-58: Consider updating deprecated addNull usage.

The addNull method is deprecated per this PR (in favor of add(paramName, QueryParamType.NULL)). While keeping deprecated methods in tests for backward compatibility validation is reasonable, consider updating or adding parallel tests with the new pattern.

balta/src/main/scala/za/co/absa/db/balta/classes/DBConnection.scala (1)

33-35: Unconventional formatting and unused parameter.

The closing parenthesis placement is unusual. Additionally, persistData is passed to ConnectionInfo but the ConnectionInfo object is only used to extract connection parameters - persistData isn't used within this apply method itself. This is consistent with the other apply overload, but worth noting that the parameter is only stored for later use by callers who access the ConnectionInfo.

Consider reformatting for consistency:

-  def apply(dbUrl: String, username: String, password: String, persistData: Boolean = false): DBConnection =
-    apply(ConnectionInfo(dbUrl, username, password, persistData)
-)
+  def apply(dbUrl: String, username: String, password: String, persistData: Boolean = false): DBConnection =
+    apply(ConnectionInfo(dbUrl, username, password, persistData))
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamType.scala (1)

32-90: Consider adding Option[T] support for nullable parameters.

Currently, to pass a nullable value, users must explicitly check for None and use QueryParamType.NULL. Adding an implicit instance for Option[T] could improve ergonomics:

implicit def SQLParamOption[T: QueryParamType]: QueryParamType[Option[T]] = new QueryParamType[Option[T]] {
  override def toQueryParamValue(value: Option[T]): QueryParamValue = value match {
    case Some(v) => implicitly[QueryParamType[T]].toQueryParamValue(v)
    case None => QueryParamValue.NullParamValue
  }
}

This would allow add("param", someOption) directly instead of pattern matching on the caller side.

balta/src/main/scala/za/co/absa/db/balta/DBTestSuite.scala (1)

133-136: Deprecation annotations are appropriate.

The deprecation of addNull methods in favor of add(NULL) (using QueryParamType.NULL) aligns with the PR objectives.

However, the type parameter T: QueryParamType on line 156 is now unnecessary since the method body calls Params.addNull() which internally uses QueryParamType.NULL. Consider simplifying:

   @deprecated("Use add(NULL)", "balta 0.3.0")
-  protected def addNull[T: QueryParamType](): OrderedParams = {
+  protected def addNull(): OrderedParams = {
     Params.addNull()
   }

Also applies to: 155-158

balta/src/main/scala/za/co/absa/db/balta/classes/DBFunction.scala (2)

119-122: Consider clarifying the deprecation message.

The deprecation message "Use setParam(NULL)" could be more explicit. Users need to pass QueryParamType.NULL, not just NULL. Consider updating the message to:

@deprecated("Use setParam(paramName, QueryParamType.NULL)", "balta 0.3.0")

This makes the migration path clearer for users.

Apply this diff to improve clarity:

-  @deprecated("Use setParam(NULL)", "balta 0.3.0")
+  @deprecated("Use setParam(paramName, QueryParamType.NULL)", "balta 0.3.0")
   def setParamNull(paramName: String): DBFunctionWithNamedParamsToo = {

178-181: Consider clarifying the deprecation message.

Similar to the named parameter version, the deprecation message could be more explicit about using QueryParamType.NULL:

Apply this diff:

-    @deprecated("Use setParam(NULL)", "balta 0.3.0")
+    @deprecated("Use setParam(QueryParamType.NULL)", "balta 0.3.0")
     def setParamNull(): DBFunctionWithPositionedParamsOnly = {
balta/src/main/scala/za/co/absa/db/balta/classes/inner/Params.scala (3)

84-86: Unused type parameter in addNull.

The type parameter [T: QueryParamType] is declared but never used in the method body. This appears unnecessary since the method always adds QueryParamType.NULL.

Consider removing the unused type parameter:

-  def addNull[T: QueryParamType](): OrderedParams = {
+  def addNull(): OrderedParams = {
     new OrderedParams().add(QueryParamType.NULL)
   }

Note: This same pattern appears in the deprecated addNull method at line 151 and in DBTestSuite.scala (lines 154-157). If there's a specific reason for the type parameter (e.g., for compatibility or implicit resolution), please document it.


114-117: Consider clarifying the deprecation message.

Similar to DBFunction.scala, the deprecation message could be more explicit:

Apply this diff:

-    @deprecated("Use add(NULL)", "balta 0.3.0")
+    @deprecated("Use add(paramName, QueryParamType.NULL)", "balta 0.3.0")
     def addNull(paramName: String): NamedParams = {

150-153: Unused type parameter and deprecation message.

This method has two issues:

  1. The type parameter [T: QueryParamType] is unused (same issue as line 84).
  2. The deprecation message could be clearer.

Apply this diff:

-    @deprecated("Use add(NULL)", "balta 0.3.0")
-    def addNull[T: QueryParamType](): OrderedParams = {
+    @deprecated("Use add(QueryParamType.NULL)", "balta 0.3.0")
+    def addNull(): OrderedParams = {
       add(QueryParamType.NULL)
     }
project/Dependencies.scala (1)

27-32: PostgreSQL now optional – good for consumers, but document the breaking aspect.

Switching postgresql to % Optional is a nice win for downstreams that don’t use Postgres, since they won’t get the driver transitively anymore. It is, however, a behaviour change: any existing consumers that relied on transitive inclusion of the JDBC driver will now need to add org.postgresql:postgresql themselves.

I’d recommend:

  • Calling this out explicitly in release notes / migration guide as a breaking change.
  • Ensuring tests cover both:
    • Code paths that work without the driver present.
    • Code paths that require Postgres, with the driver added explicitly in test dependencies.
build.sbt (1)

38-48: Enabling -deprecation and -feature is a good move; consider extending later.

Adding these options at the project level is helpful for catching misuse during this refactor, and since you’re not treating warnings as errors (here), it shouldn’t break builds—just increase signal. Over time, you might also consider -unchecked or a curated -Xlint set, but that can wait until the dust settles.

Please just verify that CI output remains manageable and that there are no unexpected new warnings across all supported Scala versions.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 35c39c7 and 6eb2fa5.

📒 Files selected for processing (24)
  • .gitignore (1 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/DBTestSuite.scala (5 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/classes/DBConnection.scala (2 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/classes/DBFunction.scala (6 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/classes/DBQuerySupport.scala (1 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/classes/DBTable.scala (10 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/classes/inner/ConnectionInfo.scala (1 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/classes/inner/Params.scala (9 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/classes/setter/AllowedParamTypes.scala (0 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/classes/setter/CustomDBType.scala (0 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/classes/setter/SetterFnc.scala (0 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/classes/simple/JsonBString.scala (0 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/implicits/package.scala (0 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/postgres/classes/SimpleJsonString.scala (2 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/postgres/implicits/Postgres.scala (1 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/postgres/typeclasses/PostgresQueryParamValue.scala (1 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamType.scala (1 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamValue.scala (1 hunks)
  • balta/src/test/scala/za/co/absa/db/balta/classes/DBTableIntegrationTests.scala (1 hunks)
  • balta/src/test/scala/za/co/absa/db/balta/implicits/PostgresRowIntegrationTests.scala (1 hunks)
  • balta/src/test/scala/za/co/absa/db/balta/testing/classes/DBTestingConnection.scala (1 hunks)
  • build.sbt (1 hunks)
  • project/Dependencies.scala (1 hunks)
  • project/build.properties (1 hunks)
💤 Files with no reviewable changes (5)
  • balta/src/main/scala/za/co/absa/db/balta/classes/setter/CustomDBType.scala
  • balta/src/main/scala/za/co/absa/db/balta/classes/setter/AllowedParamTypes.scala
  • balta/src/main/scala/za/co/absa/db/balta/classes/simple/JsonBString.scala
  • balta/src/main/scala/za/co/absa/db/balta/classes/setter/SetterFnc.scala
  • balta/src/main/scala/za/co/absa/db/balta/implicits/package.scala
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-11T08:21:36.735Z
Learnt from: benedeki
Repo: AbsaOSS/balta PR: 55
File: project/build.properties:1-1
Timestamp: 2025-09-11T08:21:36.735Z
Learning: sbt 1.11.5 and other sbt 1.x versions support and can run on JDK 8, despite common misconceptions that newer sbt versions require JDK 11+. The AbsaOSS organization has successfully released Java 8 libraries using sbt 1.11.5, as demonstrated with the spark-data-standardization library.

Applied to files:

  • project/build.properties
🧬 Code graph analysis (13)
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamValue.scala (2)
balta/src/main/scala/za/co/absa/db/balta/classes/DBFunction.scala (1)
  • sql (37-46)
balta/src/main/scala/za/co/absa/db/balta/postgres/typeclasses/PostgresQueryParamValue.scala (1)
  • assignFunc (14-16)
balta/src/test/scala/za/co/absa/db/balta/classes/DBTableIntegrationTests.scala (1)
balta/src/main/scala/za/co/absa/db/balta/classes/inner/Params.scala (2)
  • Params (28-38)
  • Params (39-157)
balta/src/main/scala/za/co/absa/db/balta/classes/DBQuerySupport.scala (1)
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamValue.scala (1)
  • QueryParamValue (28-48)
balta/src/main/scala/za/co/absa/db/balta/postgres/implicits/Postgres.scala (1)
balta/src/main/scala/za/co/absa/db/balta/postgres/classes/SimpleJsonString.scala (2)
  • SimpleJsonString (29-29)
  • SimpleJsonString (31-37)
balta/src/main/scala/za/co/absa/db/balta/postgres/typeclasses/PostgresQueryParamValue.scala (1)
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamValue.scala (2)
  • QueryParamValue (28-48)
  • assignFunc (32-34)
balta/src/test/scala/za/co/absa/db/balta/testing/classes/DBTestingConnection.scala (1)
balta/src/main/scala/za/co/absa/db/balta/classes/inner/ConnectionInfo.scala (1)
  • ConnectionInfo (28-33)
balta/src/main/scala/za/co/absa/db/balta/classes/DBConnection.scala (1)
balta/src/main/scala/za/co/absa/db/balta/classes/inner/ConnectionInfo.scala (1)
  • ConnectionInfo (28-33)
balta/src/test/scala/za/co/absa/db/balta/implicits/PostgresRowIntegrationTests.scala (2)
balta/src/main/scala/za/co/absa/db/balta/postgres/implicits/Postgres.scala (2)
  • Postgres (23-35)
  • PostgresRow (24-34)
balta/src/main/scala/za/co/absa/db/balta/postgres/classes/SimpleJsonString.scala (2)
  • SimpleJsonString (29-29)
  • SimpleJsonString (31-37)
balta/src/main/scala/za/co/absa/db/balta/postgres/classes/SimpleJsonString.scala (3)
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamType.scala (1)
  • QueryParamType (32-92)
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamValue.scala (1)
  • QueryParamValue (28-48)
balta/src/main/scala/za/co/absa/db/balta/postgres/typeclasses/PostgresQueryParamValue.scala (2)
  • PostgresQueryParamValue (8-21)
  • PostgresObjectQueryParamValue (9-18)
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamType.scala (4)
balta/src/main/scala/za/co/absa/db/balta/classes/DBFunction.scala (1)
  • sql (37-46)
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamValue.scala (4)
  • QueryParamValue (28-48)
  • SimpleQueryParamValue (38-40)
  • ObjectQueryParamValue (31-36)
  • NullParamValue (42-46)
balta/src/main/scala/za/co/absa/db/balta/postgres/classes/SimpleJsonString.scala (1)
  • toQueryParamValue (35-35)
balta/src/main/scala/za/co/absa/db/balta/implicits/OptionImplicits.scala (1)
  • value (37-37)
balta/src/main/scala/za/co/absa/db/balta/DBTestSuite.scala (3)
balta/src/main/scala/za/co/absa/db/balta/classes/inner/Params.scala (12)
  • Params (28-38)
  • Params (39-157)
  • NamedParams (93-122)
  • OrderedParams (129-156)
  • add (50-52)
  • add (73-75)
  • add (102-105)
  • add (137-141)
  • addNull (61-63)
  • addNull (84-86)
  • addNull (114-117)
  • addNull (150-153)
balta/src/main/scala/za/co/absa/db/balta/classes/DBFunction.scala (2)
  • DBFunction (34-132)
  • DBFunction (135-195)
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamType.scala (1)
  • QueryParamType (32-92)
balta/src/main/scala/za/co/absa/db/balta/classes/inner/Params.scala (3)
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamValue.scala (1)
  • QueryParamValue (28-48)
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamType.scala (16)
  • QueryParamType (32-92)
  • NULL (86-86)
  • toQueryParamValue (35-35)
  • toQueryParamValue (39-39)
  • toQueryParamValue (43-43)
  • toQueryParamValue (47-47)
  • toQueryParamValue (51-51)
  • toQueryParamValue (55-55)
  • toQueryParamValue (59-59)
  • toQueryParamValue (63-63)
  • toQueryParamValue (67-67)
  • toQueryParamValue (71-71)
  • toQueryParamValue (75-75)
  • toQueryParamValue (79-79)
  • toQueryParamValue (83-83)
  • toQueryParamValue (89-89)
balta/src/main/scala/za/co/absa/db/balta/DBTestSuite.scala (4)
  • add (123-125)
  • add (145-147)
  • addNull (133-136)
  • addNull (155-158)
balta/src/main/scala/za/co/absa/db/balta/classes/DBFunction.scala (2)
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamValue.scala (1)
  • QueryParamValue (28-48)
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamType.scala (16)
  • QueryParamType (32-92)
  • toQueryParamValue (35-35)
  • toQueryParamValue (39-39)
  • toQueryParamValue (43-43)
  • toQueryParamValue (47-47)
  • toQueryParamValue (51-51)
  • toQueryParamValue (55-55)
  • toQueryParamValue (59-59)
  • toQueryParamValue (63-63)
  • toQueryParamValue (67-67)
  • toQueryParamValue (71-71)
  • toQueryParamValue (75-75)
  • toQueryParamValue (79-79)
  • toQueryParamValue (83-83)
  • toQueryParamValue (89-89)
  • NULL (86-86)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Scala 2.11.12
🔇 Additional comments (37)
.gitignore (1)

38-40: LGTM!

The additions of .metals/, .bloop/, and metals.sbt to the VS Code tooling section are appropriate and follow existing conventions. These entries correctly exclude Scala language server and build tool artifacts that should not be committed.

balta/src/test/scala/za/co/absa/db/balta/testing/classes/DBTestingConnection.scala (1)

20-20: LGTM!

Import path correctly updated to reflect the package move of ConnectionInfo to the inner package.

balta/src/test/scala/za/co/absa/db/balta/classes/DBTableIntegrationTests.scala (1)

20-20: LGTM!

Import path correctly updated to reflect the package move of Params to the inner package.

balta/src/main/scala/za/co/absa/db/balta/postgres/typeclasses/PostgresQueryParamValue.scala (1)

8-21: LGTM!

The PostgresObjectQueryParamValue implementation correctly extends QueryParamValue and efficiently creates the PGobject once during construction. The assignFunc properly binds the object to the PreparedStatement.

balta/src/test/scala/za/co/absa/db/balta/implicits/PostgresRowIntegrationTests.scala (1)

21-22: LGTM!

Import paths correctly updated to reflect the new package structure for PostgresRow and SimpleJsonString under the postgres package.

balta/src/main/scala/za/co/absa/db/balta/postgres/implicits/Postgres.scala (2)

17-21: LGTM!

Package path and import correctly updated to align with the new Postgres-specific package structure.


23-34: LGTM!

The PostgresRow implicit class correctly provides extension methods for retrieving SimpleJsonString values from query results. The removal of deprecated JsonBString support aligns with the PR objectives.

balta/src/main/scala/za/co/absa/db/balta/classes/DBQuerySupport.scala (1)

27-40: LGTM!

The refactored runQuery method correctly iterates over QueryParamValue instances, binding parameters via assign when present and skipping index increment for NullParamValue (where assign is None). The foldLeft pattern cleanly manages the parameter index.

balta/src/main/scala/za/co/absa/db/balta/postgres/classes/SimpleJsonString.scala (2)

17-22: LGTM!

Package and imports correctly updated to reflect the Postgres-specific location and new typeclass infrastructure.


31-37: LGTM!

The companion object provides a clean typeclass implementation for SimpleJsonString. The implicit QueryParamType[SimpleJsonString] correctly delegates to PostgresObjectQueryParamValue with the "json" PostgreSQL type, enabling seamless parameter binding.

balta/src/main/scala/za/co/absa/db/balta/classes/DBConnection.scala (2)

19-20: LGTM on imports.

The imports are correctly updated to reference ConnectionInfo from the new inner package, and implicitConversions is appropriately imported for the new implicit conversion.


37-40: LGTM on implicit conversion.

The implicit conversion enables seamless use of DBConnection wherever a JDBC Connection is expected. This aligns with the PR's goal of improving ergonomics and replaces the removed implicit from balta/implicits/package.scala.

balta/src/main/scala/za/co/absa/db/balta/classes/DBTable.scala (4)

44-46: LGTM on insert method updates.

The method correctly uses values.values.map(_.sqlEntry) to build the SQL parameter placeholders and passes values.values (the List[QueryParamValue]) to runQuery. This aligns with the new value-based binding approach.


61-61: LGTM on fieldValue signature change.

The context bound change from AllowedParamTypes to QueryParamType correctly adopts the new typeclass-based constraint, enabling proper implicit resolution for key values.


217-223: LGTM on private compose methods.

The signature updates to accept List[QueryParamValue] with a default empty list are consistent across all three methods, and the integration with runQuery is correct.

Also applies to: 226-231, 234-240


251-256: LGTM on WHERE condition generation.

The use of value.equalityOperator (which returns "IS" for NULL and "=" otherwise) and value.sqlEntry (which returns "NULL" or "?") correctly handles both regular values and NULLs in WHERE clauses.

balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamType.scala (3)

28-30: Clean typeclass design.

The QueryParamType[T] trait with a single toQueryParamValue method is appropriately minimal and focused. This design enables extensibility for custom types (like the Postgres-specific SimpleJsonString shown in the snippets).


34-84: Good coverage of common SQL types.

The implicit instances cover the most commonly used SQL parameter types. The conversions are appropriate:

  • InstantOffsetDateTime at UTC is a safe default
  • BigDecimaljava.math.BigDecimal via .bigDecimal is correct
  • CharString via .toString handles single-character values properly

86-90: Elegant NULL representation.

Using a singleton NULL object with its own typeclass instance is a clean pattern that integrates well with the add(QueryParamType.NULL) API, replacing the deprecated addNull methods.

balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamValue.scala (3)

22-26: Well-designed abstraction.

The QueryParamValue trait cleanly encapsulates three concerns:

  1. How to bind the value (assign)
  2. What to emit in SQL (sqlEntry)
  3. How to compare for equality in WHERE clauses (equalityOperator)

The defaults ("?" and "=") work for most cases while allowing NullParamValue to override appropriately.


31-40: LGTM on concrete implementations.

ObjectQueryParamValue and SimpleQueryParamValue correctly implement the trait with Some(assignFunc) for their assign values. The private assignFunc in ObjectQueryParamValue properly encapsulates the implementation detail.


42-46: Correct NULL semantics.

NullParamValue correctly:

  • Returns None for assign (no PreparedStatement binding needed)
  • Uses "NULL" literal in SQL instead of a placeholder
  • Uses "IS" for equality checks (SQL standard: column IS NULL not column = NULL)
balta/src/main/scala/za/co/absa/db/balta/DBTestSuite.scala (1)

123-125: LGTM on add method updates.

The context bound change from AllowedParamTypes to QueryParamType is correct and consistent with the typeclass refactoring throughout the codebase.

Also applies to: 145-147

balta/src/main/scala/za/co/absa/db/balta/classes/DBFunction.scala (4)

22-22: LGTM: Import updated for typeclass refactoring.

The import correctly brings in the new QueryParamType and QueryParamValue types that replace the old AllowedParamTypes and SetterFnc.


106-110: LGTM: Typeclass pattern correctly implemented.

The setParam method properly uses the QueryParamType context bound and converts values through the typeclass interface. The implementation is type-safe and consistent with the refactoring goals.


137-137: LGTM: Type alias correctly updated.

The ParamsMap type alias now uses QueryParamValue instead of SetterFnc, which is consistent with the typeclass-based refactoring.


166-170: LGTM: Positioned parameter handling correctly refactored.

The setParam method for positioned parameters correctly implements the typeclass pattern, consistent with the named parameter version.

balta/src/main/scala/za/co/absa/db/balta/classes/inner/Params.scala (9)

17-17: LGTM: Package reorganization.

The move to the inner package reflects the architectural reorganization mentioned in the PR objectives.


20-20: LGTM: Imports updated correctly.

The import statement properly brings in the new typeclass types.


28-36: LGTM: Base class correctly refactored.

The Params abstract class properly uses QueryParamValue throughout, and the public API (values, apply) correctly reflects the new types.


50-63: LGTM: Named parameter factory methods correctly implemented.

Both add and addNull factory methods properly use the typeclass pattern. The delegation from addNull to add with QueryParamType.NULL is appropriate.


73-75: LGTM: Ordered parameter factory method.

The add factory method correctly uses the QueryParamType context bound.


93-93: LGTM: NamedParams constructor updated.

The constructor properly uses QueryParamValue in the internal map.


102-105: LGTM: Type-safe parameter addition.

The add method correctly uses implicitly[QueryParamType[T]].toQueryParamValue(value) to convert values through the typeclass, ensuring type safety.


119-119: LGTM: pairs method updated.

The return type correctly reflects the new QueryParamValue type.


129-141: LGTM: OrderedParams implementation.

The OrderedParams class correctly implements parameter addition using the typeclass pattern. The key generation (items.size.toString) and value conversion are properly handled.

project/build.properties (1)

1-1: Patch-level sbt upgrade looks good; just confirm your JDK matrix.

Bumping from 1.11.5 to 1.11.7 keeps you within the same major/minor line and should be low-risk, especially given prior experience with sbt 1.x on JDK 8 in this org. Still, it’s worth confirming your oldest supported JDK passes CI with this version (and that all sbt plugins still resolve cleanly). Based on learnings, sbt 1.11.x is expected to continue running on JDK 8, but verification in your pipeline is recommended.


object NULL

implicit object SQLParamNull extends QueryParamType[NULL.type] {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about the custom type? I remember that we use this on many places

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be now done via it's own type-class implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

class MyType {
}

implicit object QueryParamMyClasse xtendes QueryParamType[MyClass] {
   override def toQueryParamValue(value: MyClass): QueryParamValue = ???
}

Copy link
Collaborator

@lsulak lsulak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I gave it a read and I like the changes although some are not backward compatible - perhaps it can be part of the major version release v1.0.0 probably.

I asked a Q about Custom DB type and also the AI Agent is telling you about some unused imports (not sure if false positives?)

Also I think RNs check is failing because the format is off in PR description but that can be easily fixed

@benedeki
Copy link
Contributor Author

I gave it a read and I like the changes although some are not backward compatible - perhaps it can be part of the major version release v1.0.0 probably.

Yes, it has breaking changes. But IMHO this approach is one of the preconditions for v1.0.0 (probably the only one crucial, although I still might do the column names bug).
So absolutely let's make it into the first non-prerelease. 😉

I asked a Q about Custom DB type and also the AI Agent is telling you about some unused imports (not sure if false positives?)
Replied inline about the custom type.
AI might be right, VS Code doesn't show that nicely unused imports, or at least I haven learned yet how to find it.

Also I think RNs check is failing because the format is off in PR description but that can be easily fixed
Ah, missed that it's present here (funnily even asked @miroslavpojer to add it)

* unified implicit object names to adhere to trait name
* removed the usage of obsolete functions in tests
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
balta/src/main/scala/za/co/absa/db/balta/postgres/classes/SimpleJsonString.scala (1)

32-32: Consider the scope impact of the implicit conversion.

The implicit conversion from String to SimpleJsonString provides convenience but may lead to unintended conversions when SimpleJsonString is imported. Since this is a deliberate design choice for a value class and part of the v1.0.0 API, verify that the automatic conversion behavior aligns with your intended usage patterns.

balta/src/main/scala/za/co/absa/db/balta/DBTestSuite.scala (1)

154-157: Verify deprecation consistency.

The addNull[T: QueryParamType]() method retains the type parameter constraint, but since it always returns a NULL value, the type parameter seems vestigial. Consider whether the signature should be simplified to addNull() without the type parameter, matching the simpler add(NULL) replacement pattern.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6eb2fa5 and 6d21d80.

📒 Files selected for processing (6)
  • balta/src/main/scala/za/co/absa/db/balta/DBTestSuite.scala (5 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/classes/DBQuerySupport.scala (1 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/classes/DBTable.scala (10 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/postgres/classes/SimpleJsonString.scala (2 hunks)
  • balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamType.scala (1 hunks)
  • balta/src/test/scala/za/co/absa/db/balta/classes/DBTableIntegrationTests.scala (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • balta/src/test/scala/za/co/absa/db/balta/classes/DBTableIntegrationTests.scala
🧰 Additional context used
🧬 Code graph analysis (3)
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamType.scala (3)
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamValue.scala (4)
  • QueryParamValue (28-48)
  • SimpleQueryParamValue (38-40)
  • ObjectQueryParamValue (31-36)
  • NullParamValue (42-46)
balta/src/main/scala/za/co/absa/db/balta/postgres/classes/SimpleJsonString.scala (1)
  • toQueryParamValue (35-35)
balta/src/main/scala/za/co/absa/db/balta/implicits/OptionImplicits.scala (1)
  • value (37-37)
balta/src/main/scala/za/co/absa/db/balta/postgres/classes/SimpleJsonString.scala (3)
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamType.scala (15)
  • QueryParamType (32-92)
  • toQueryParamValue (35-35)
  • toQueryParamValue (39-39)
  • toQueryParamValue (43-43)
  • toQueryParamValue (47-47)
  • toQueryParamValue (51-51)
  • toQueryParamValue (55-55)
  • toQueryParamValue (59-59)
  • toQueryParamValue (63-63)
  • toQueryParamValue (67-67)
  • toQueryParamValue (71-71)
  • toQueryParamValue (75-75)
  • toQueryParamValue (79-79)
  • toQueryParamValue (83-83)
  • toQueryParamValue (89-89)
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamValue.scala (1)
  • QueryParamValue (28-48)
balta/src/main/scala/za/co/absa/db/balta/postgres/typeclasses/PostgresQueryParamValue.scala (2)
  • PostgresQueryParamValue (8-21)
  • PostgresObjectQueryParamValue (9-18)
balta/src/main/scala/za/co/absa/db/balta/classes/DBQuerySupport.scala (2)
balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamValue.scala (1)
  • QueryParamValue (28-48)
balta/src/main/scala/za/co/absa/db/balta/classes/DBFunction.scala (1)
  • sql (37-46)
🔇 Additional comments (11)
balta/src/main/scala/za/co/absa/db/balta/postgres/classes/SimpleJsonString.scala (2)

17-22: Package structure and imports are correct.

The package placement aligns with the Postgres-specific code organization, and all imports are actually used in the implementation below. Contrary to concerns mentioned in the PR comments about potentially unused imports, this file has no unused imports.


34-36: Typeclass implementation is correct.

The QueryParamType[SimpleJsonString] instance correctly follows the typeclass pattern and properly delegates to PostgresObjectQueryParamValue with the "json" type, consistent with the repository's new parameter binding approach.

balta/src/main/scala/za/co/absa/db/balta/classes/DBQuerySupport.scala (1)

31-38: LGTM! Correct handling of NULL parameter binding.

The foldLeft logic properly distinguishes between bound parameters (Some(assignFnc)) which require PreparedStatement binding and NULL values (None) which are embedded directly as SQL literals. The parameter index correctly advances only for bound values.

balta/src/main/scala/za/co/absa/db/balta/typeclasses/QueryParamType.scala (3)

28-30: Clean typeclass design.

The QueryParamType[T] trait provides a well-structured abstraction for converting Scala/Java types to JDBC-compatible parameter values. This enables ad-hoc polymorphism and easy extensibility for custom types.


66-68: UTC zone hardcoded for Instant conversion.

The InstantOffsetDateTime conversion assumes UTC. This is a reasonable default for DB storage, but users needing a different timezone can explicitly convert to OffsetDateTime before passing.


86-90: Well-designed NULL representation.

The NULL singleton object with its typeclass instance cleanly integrates SQL NULL semantics into the typeclass system. This enables add(QueryParamType.NULL) usage as recommended in the deprecation messages.

balta/src/main/scala/za/co/absa/db/balta/DBTestSuite.scala (2)

122-124: Type constraint updated correctly.

The migration from AllowedParamTypes to QueryParamType context bound aligns with the new typeclass-based parameter handling.


132-135: Deprecation annotation is properly informative.

The deprecation message clearly directs users to the new add(NULL) pattern and specifies the version when deprecated.

balta/src/main/scala/za/co/absa/db/balta/classes/DBTable.scala (3)

19-21: Imports correctly updated.

The imports now reference the new inner.Params structure and include both QueryParamValue and QueryParamType as needed for the refactored implementation.


249-254: Correct SQL NULL comparison semantics.

The paramsToWhereCondition logic properly handles NULL values by using value.equalityOperator (which is "IS" for NULL) and value.sqlEntry (which is "NULL" for NULL), producing correct SQL like fieldName IS NULL instead of the incorrect fieldName = NULL.


42-44: INSERT parameter binding looks correct.

The sqlEntry values (placeholders ? for bound values, literal NULL for nulls) are correctly interpolated into the SQL, and values.values is passed to runQuery for PreparedStatement binding.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
.github/workflows/check_pr_release_notes.yml (1)

17-17: Minor: Slightly redundant workflow and job naming.

The workflow name contains "Release Notes Presence Check" and the job display name is also "Release Notes Presence Check," which is somewhat repetitive. Consider shortening the workflow name to something like "Check Release Notes Presence" or the job name to just "Check Release Notes" to reduce redundancy.

Also applies to: 25-26

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6d21d80 and aa8df0e.

📒 Files selected for processing (1)
  • .github/workflows/check_pr_release_notes.yml (1 hunks)
🔇 Additional comments (3)
.github/workflows/check_pr_release_notes.yml (3)

17-41: Good: Migration to a dedicated external action improves maintainability.

Replacing custom inline GitHub Script logic with a standardized external action is a solid move. This reduces maintenance burden and allows the team to focus on business logic rather than workflow orchestration. The change aligns well with the PR's broader shift toward modular, standardized approaches.


34-41: All parameters and version are correctly configured; no issues identified.

The verification confirms:

  1. Action version: AbsaOSS/release-notes-presence-check@v0.4.0 exists and is actively maintained.
  2. Parameters: All three parameters are correctly named according to the action's documentation:
    • github-repository
    • pr-number
    • skip-labels
  3. Skip-label convention: The label "no RN" is consistently used across the project's workflows (also appears in release_draft.yml as skip-release-notes-label: "no RN"), confirming it aligns with established project conventions.

The workflow configuration is accurate and follows the project's established patterns.


30-32: Based on my verification, I've found critical information about this workflow setup:

Key Findings:

  1. The action AbsaOSS/release-notes-presence-check@v0.4.0 referenced in line 35 does not exist in public GitHub
  2. A similar action AbsaOSS/generate-release-notes@v0.4.0 DOES exist and is Python-based (found in release_draft.yml with identical Python 3.11 setup)
  3. No Python code execution occurs in the check_pr_release_notes.yml workflow after the setup
  4. The Python setup appears to have been copy-pasted from release_draft.yml but may be unnecessary for the non-existent or private action being referenced

Verify that the external action AbsaOSS/release-notes-presence-check@v0.4.0 exists and requires Python 3.11.

The referenced action does not appear in the GitHub Marketplace or public AbsaOSS repositories. A similarly named action (AbsaOSS/generate-release-notes@v0.4.0) exists and is Python-based, suggesting the Python setup may have been incorrectly copied. If this action is private or the reference is incorrect, the Python setup step may be unnecessary and should be removed or the action reference clarified.

@benedeki benedeki merged commit d4b9221 into master Nov 27, 2025
11 checks passed
@benedeki benedeki deleted the feature/52-use-type-classe-for-allowedparamtypes branch November 27, 2025 10:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking change Introduces change, that is incompatible with last release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use type classe for AllowedParamTypes

2 participants