Skip to content

Define a SQL-first contract for Hibernate ORM and Spring Data repositories #12

Description

@asmyasnikov

Context

PR #2 generated Java query APIs for Hibernate and Spring by executing the original YQL through JDBC obtained from the framework:

  • the Hibernate profile used Session.doReturningWork(...) and PreparedStatement;
  • the Spring profile used JdbcTemplate and ConnectionCallback.

PR #11 explored idiomatic ORM/repository APIs instead:

  • Hibernate Session and Jakarta Persistence EntityManager operations such as find, persist, merge, and remove, plus JPQL queries;
  • a Spring Data JDBC CrudRepository with derived query methods and inherited CRUD operations.

Neither approach currently provides a useful SQL-first generator. The JDBC-through-framework output preserves the input YQL, but merely duplicates the JDBC generator behind another abstraction. The ORM/repository output is idiomatic, but changes the source of truth: an input UPSERT may become merge, CRUD methods appear without named input queries, and YQL may be replaced with JPQL inferred from entities and schema.

The current spring runtime is a direct Spring JDBC adapter, not the Spring Data JDBC repository from PR #11 and not Spring Data JPA. Both the spring and hibernate targets are being removed until an explicit SQL-first contract for framework integration is defined.

Why YQL-to-JPQL translation is not general

A restricted translation is possible. For example:

SELECT id, name, bio FROM authors WHERE id = $author_id;

could become:

SELECT a FROM Authors a WHERE a.id = :authorId

JPQL addresses entities and Java properties, while YQL addresses tables, columns, YDB types, and YQL expressions. Correct translation therefore also requires deterministic mappings for tables, columns, parameters, projections, and nullability.

Valid YQL constructs including YDB-specific types and functions, DECLARE, UPSERT, RETURNING, AS_TABLE, and table hints do not have general JPQL equivalents. Joins, aggregates, partial projections, and results that are not a single entity also need explicit behavior. Silent semantic changes or implicit fallback would make generated code hard to trust.

Questions to resolve

  1. Can a framework target remain SQL-first by generating one method for every named query and executing the original YQL through an idiomatic API such as Hibernate createNativeQuery(...) or an appropriate Spring Data native-query mechanism?
  2. Can those APIs preserve YDB parameter types, result mappings, transaction ownership, and mutation semantics without dropping to raw JDBC?
  3. Which result forms should be supported: entities, scalar values, DTO projections, tuples, or all of them?
  4. Should entity classes be generated from the schema, supplied by the user, or configured through explicit mappings?
  5. Should unsupported queries fail generation, or may a fallback be enabled explicitly?
  6. Is a deliberately restricted YQL-to-JPQL subset useful enough to maintain?

Acceptance criteria for restoring a target

  • Every generated method maps to a named input query; no CRUD methods are invented from the schema.
  • Original YQL semantics are preserved. Translations use a documented subset, and unsupported input fails with an actionable diagnostic.
  • Generated code uses an idiomatic public framework API instead of only obtaining a JDBC connection from it.
  • Table, column, entity-property, parameter, nullability, and projection mappings are explicit and deterministic.
  • Transaction ownership, retry responsibility, and mutation semantics are documented in the generated API.
  • Examples compile against supported framework versions and pass integration tests against YDB.
  • Fixtures cover entity, scalar and DTO results, joins, mutations, and representative unsupported YQL constructs.

Related: #2, #11.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions