ygrek / sqlgg

SQL Guided (code) Generator
https://ygrek.org/p/sqlgg/
GNU General Public License v2.0
61 stars 20 forks source link

Introduce shortcut syntax for optional bool in `WHERE` expr #142

Open jongleb opened 1 month ago

jongleb commented 1 month ago

This PR adds new syntaxes:

1) @param :: Type? 2) WHERE A? AND B? OR C? which is a shortcut to WHERE @choice { None { TRUE } | Some (params) { A } } AND etc 3) WHERE A! AND B! OR C! which expands to WHERE @choice { None { FALSE } | Some { A } } AND etc

And considers join_cond as not null by the default

Example:

DDL:

CREATE TABLE test19 (
  a INT NOT NULL,
  b INT NOT NULL
);
CREATE TABLE test20 (
  c INT NOT NULL,
  d INT NOT NULL,
  r TEXT NOT NULL
);

SQL:

SELECT *
FROM test19
LEFT JOIN test20 on test20.c = @test20a
WHERE { c = @choice2 }? AND { r = @choice3 }! AND r = @var3
GROUP BY b;

will be generated the following code:

let test db ~test20a ~choice2 ~choice3 ~var3 callback =
    let invoke_callback stmt =
      callback
        ~a:(T.get_column_Int stmt 0)
        ~b:(T.get_column_Int stmt 1)
        ~c:(T.get_column_Int_nullable stmt 2)
        ~d:(T.get_column_Int_nullable stmt 3)
        ~r:(T.get_column_Text_nullable stmt 4)
    in
    let set_params stmt =
      let p = T.start_params stmt (4) in
      T.set_param_Int p test20a;
      begin match choice2 with
      | None -> ()
      | Some (choice2) ->
        T.set_param_Int p choice2;
      end;
      begin match choice3 with
      | None -> ()
      | Some (choice3) ->
        T.set_param_Text p choice3;
      end;
      T.set_param_Text p var3;
      T.finish_params p
    in
    T.select db ("SELECT *\n\
FROM test19\n\
LEFT JOIN test20 on test20.c = ?\n\
WHERE " ^ (match choice2 with Some _ -> " c = " ^ "?" ^ " " | None -> " TRUE ") ^ " AND " ^ (match choice3 with Some _ -> " r = " ^ "?" ^ " " | None -> " FALSE ") ^ " AND r = ?\n\
GROUP BY b") set_params invoke_callback

Also, it differs from the regular Choice in that, in this case, not a polymorphic variant is generated because for this case, it would lead to the useless matching from the regular option type to the poly version of the option in the user code.

ygrek commented 1 week ago

didn't look at the code

  1. why is :: Type? here?
  2. So it means if A? OR B? and both are None - then condition is true and everything is selected.
  3. What is expected usage ratio for A! and A? One obviously can be expressed with the other (or via current manual unwrapping), so if one is very low use - i would prefer to not introduce extra syntax.
jongleb commented 2 days ago

why is :: Type? here?

Just shortcut Remove?

So it means if A? OR B? and both are None - then condition is true and everything is selected.

Yes, something like with COALESCE (maybe a bad analogy), while the first is not null - type is always null

What is expected usage ratio for A! and A? One obviously can be expressed with the other (or via current manual unwrapping), so if one is very low use - i would prefer to not introduce extra syntax.

Ok I'll remove it

ygrek commented 1 day ago

ok, so keep this PR only about introducing automatic elimination for A? OR B? I am also slightly uneasy about ::Type? precisely because it means different thing from WHERE A? which may be possibly confusing? Maybe it is worth to be more explicit with :: Maybe Type or some such or maybe I am overthinking