andrenth / sequoia

OCaml type-safe query builder with syntax tree extension
123 stars 16 forks source link

Aliases for tables. #12

Open NightBlues opened 5 years ago

NightBlues commented 5 years ago

There are alias and --> funcitons in Sequoia.Select, but they operate over Expr.t while tables are not expressions. Example:

module Weapon = struct
  include (val Postgresql.table "weapon")
  let id = Field.int "id"
  let name = Field.string "name"
  let damage = Field.int "damage"
end

module Unit = struct
  include (val Postgresql.table "unit")
  let id = Field.int "id"
  let name = Field.string "name"
  let main_hand = Field.foreign_key "main_hand" ~references:Weapon.id
  let off_hand = Field.foreign_key "off_hand" ~references:Weapon.id
end    

let list_query =
  Postgresql.Select.(Expr.(
      from Unit.table
      |> left_join (that Unit.main_hand There)
      |> left_join (that Unit.off_hand (Skip There))
      |> select [
        field Unit.id (Skip (Skip (There)));
        field Unit.name (Skip (Skip (There)));
        field Weapon.name There;
        field Weapon.damage There;
        field Weapon.name (Skip There);
        field Weapon.damage (Skip There);
      ]
      |> seal
    ))

generates following sql:

SELECT unit.id, unit.name, weapon.name, weapon.damage, weapon.name, weapon.damage
FROM unit
LEFT JOIN weapon ON weapon.id = unit.main_hand
LEFT JOIN weapon ON weapon.id = unit.off_hand

which seems to be not valid.

Whould be cool to have ability to do something like:

let list_query =
  Postgresql.Select.(Expr.(
      from Unit.table
      |> (left_join (that Unit.main_hand There) --> "mainhand")
      |> (left_join (that Unit.off_hand (Skip There)) --> "offhand")
      |> select [
        field Unit.id (Skip (Skip (There)));
        field Unit.name (Skip (Skip (There)));
        field Weapon.name There;
        field Weapon.damage There;
        field Weapon.name (Skip There);
        field Weapon.damage (Skip There);
      ]
      |> seal
    ))

and get sql:

SELECT unit.id, unit.name, mainhand.name, mainhand.damage,
offhand.name, offhand.damage
FROM unit
LEFT JOIN weapon AS mainhand ON weapon.id = unit.main_hand
LEFT JOIN weapon AS offhand ON weapon.id = unit.off_hand

Excuse me, if I'm missing something - types are hard enough to understand:) May be a workaround can exist?