Skip to content

Type mappings for columns#192

Merged
jongleb merged 1 commit intoygrek:masterfrom
jongleb:osfriday-8
May 15, 2025
Merged

Type mappings for columns#192
jongleb merged 1 commit intoygrek:masterfrom
jongleb:osfriday-8

Conversation

@jongleb
Copy link
Copy Markdown
Collaborator

@jongleb jongleb commented May 10, 2025

Description

This PR adds the ability to customize how column values are handled in SELECT queries using simple annotations. You can now easily convert database types to your domain types directly in table definitions.

How it works

  • Custom column value mapping using -- [sqlgg] comments in table definitions
  • Support for module-level customization with module=Module_name annotation
  • Optional function-level customization with get_column=function_name annotation
  • Automatic handling of both nullable and non-nullable column values

Usage Example

CREATE TABLE orders (
  -- [sqlgg] module=UUID
  id CHAR(36) PRIMARY KEY,
  
  -- [sqlgg] module=Money
  -- [sqlgg] get_column=cents_to_dollars
  amount BIGINT NOT NULL,
  
  -- [sqlgg] module=DateTime
  created_at DATETIME NOT NULL,
  
  status TEXT NOT NULL
);

And query

-- @select_orders
SELECT id, amount, created_at, status FROM orders;

This generates code that:

  • Converts id from string to UUID object via UUID.get_column
  • Transforms amount from cents (stored as BIGINT) to dollars using Money.cents_to_dollars
  • Parses created_at into proper datetime with DateTime.get_column
  • Leaves status with default trait implementation

Example Generated Code

let select_orders db callback =
  let invoke_callback stmt =
    callback
      ~id:(UUID.get_column (T.get_column_Text stmt 0))
      ~amount:(Money.cents_to_dollars (T.get_column_int64 stmt 1))
      ~created_at:(DateTime.get_column (T.get_column_datetime stmt 2))
      ~status:(T.get_column_Text stmt 3)
  in
  T.select db "SELECT id, amount, created_at, status FROM orders" T.no_params invoke_callback

With these custom conversions, application code can work directly with domain types:

let total_sales db =
  Sqlgg.Fold.select_orders db 
    (fun ~id ~amount ~created_at ~status acc -> 
      let open Money in
     (* let (+) a b = ... *)
      acc + amount)
    Money.zero

Future Work

  • Support for customizing parameter handling in WHERE clauses
  • Support for DML operations (INSERT/UPDATE)
  • Implementation for other target languages

@jongleb jongleb changed the title type mappings for columns Type mappings for columns May 13, 2025
@jongleb jongleb marked this pull request as ready for review May 13, 2025 10:56
@jongleb jongleb merged commit 89a256a into ygrek:master May 15, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant