From 2d9ceb73a60864f7691583d619956face67a5220 Mon Sep 17 00:00:00 2001 From: Sean Corfield Date: Sat, 13 Feb 2021 21:10:49 -0800 Subject: [PATCH] Expand documentation --- doc/getting-started.md | 131 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/doc/getting-started.md b/doc/getting-started.md index 0233b8e..98307a7 100644 --- a/doc/getting-started.md +++ b/doc/getting-started.md @@ -96,6 +96,69 @@ the table name, i.e., `:foo/bar` instead of `:foo.bar`: ;;=> ["SELECT t.id, name AS item FROM table AS t WHERE id = ?" 1] ``` +## SQL Expressions + +In addition to using hash maps to describe SQL clauses, +HoneySQL uses vectors to describe SQL expressions. Any +sequence that begins with a keyword (or symbol) is considered +to be a kind of function invocation. Certain "functions" are +considered to be "special syntax" and have custom rendering. +Some "functions" are considered to be operators. In general, +`[:foo :a 42 "c"]` will render as `FOO(a, ?, ?)` with the parameters +`42` and `"c"` lifted out into the overall vector result +(with a SQL string followed by all its parameters). + +Operators can be strictly binary or variadic (most are strictly binary). +Special syntax can have zero or more arguments and each form is +described in the [docs/special-syntax.md](Special Syntax) section. + +Some examples: + +```clojure +[:= :a 42] ;=> "a = ?" with a parameter of 42 +[:+ 42 :a :b] ;=> "? + a + b" with a parameter of 42 +[:= :x [:inline "foo"]] ;=> "x = 'foo'" -- the string is inlined +[:now] ;=> "NOW()" +[:count :*] ;=> "COUNT(*)" +[:or [:<> :name nil] [:= :status-id 0]] ;=> "(name IS NOT NULL) OR (status_id = ?)" +;; with a parameter of 0 -- the nil value is inlined as NULL +``` + +`:inline` is an example of "special syntax" and it renders its +(single) argument as part of the SQL string generated by `format`. + +## SQL Parameters + +As indicated in the preceding sections, values found in the DSL data structure +that are not keywords or symbols are lifted out as positional parameters. +They are replaced by `?` in the generated SQL string and added to the +parameter list in order: + +```clojure +[:between :size 10 20] ;=> "size BETWEEN ? AND ?" with parameters 10 and 20 +``` + +HoneySQL also supports named parameters. There are two ways +of identifying a named parameter: +* a keyword or symbol that begins with `?` +* the `:param` special (functional) syntax + +The values of those parameters are supplied in the `format` +call as the `:params` key of the options hash map. + +```clojure +(sql/format {:select [:*] :from [:table] + :where [:= :a :?x]} + {:params {:x 42}}) +["SELECT * FROM table WHERE a = ?" 42] +(sql/format {:select [:*] :from [:table] + :where [:= :a [:param :x]]} + {:params {:x 42}}) +["SELECT * FROM table WHERE a = ?" 42] +``` + +## Functional Helpers + In addition to the hash map (and vectors) approach of building SQL queries with raw Clojure data structures, a namespace full of helper functions is also available. These functions are @@ -156,10 +219,78 @@ you need to consider this when referring symbols in from the `honey.sql.helpers` namespace: `for`, `group-by`, `partition-by`, `set`, and `update`. +## Dialects + +By default, HoneySQL operates in ANSI SQL mode but it supports +a lot of PostgreSQL extensions in that mode. PostgreSQL is mostly +a superset of ANSI SQL so it makes sense to support as much as +possible of the union of ANSI SQL and PostgreSQL out of the box. + +The dialects supported by HoneySQL v2 are: +* `:ansi` -- the default, including most PostgreSQL extensions +* `:sqlserver` -- Microsoft SQL Server +* `:mysql` -- MySQL (and Percona and MariaDB) +* `:oracle` -- Oracle + +The most visible difference between dialects is how SQL entities +should be quoted (if the `:quoted true` option is provided to `format`). +Most databases use `"` for quoting (the `:ansi` and `:oracle` dialects). +The `:sqlserver` dialect uses `[`..`]` and the `:mysql` dialect uses +```..```. + +Currently, the only dialect that has substantive differences from +the others is `:mysql` which has a `:lock` clause (that is very +similar to the ANSI `:for` clause) and for which the `:set` clause +has a different precedence than ANSI SQL. + +You can change the dialect globally using the `set-dialect!` function, +passing in one of the keywords above. You need to call this function +before you call `format` for the first time. + +You can change the dialect for a single `format` call by +specifying the `:dialect` option in that call. + +SQL entities are not quoted by default but if you specify the +dialect in a `format` call, they will be quoted. If you don't +specify a dialect in the `format` call, you can specify +`:quoted true` to have SQL entities quoted. + +```clojure +(sql/format '{select (id) from (table)} {:quoted true}) +;;=> ["SELECT \"id\" FROM \"table\""] +(sql/format '{select (id) from (table)} {:dialect :mysql}) +;;=> ["SELECT `id` FROM `table`"] +(sql/set-dialect! :sqlserver) +;;=> nil +(sql/format '{select (id) from (table)} {:quoted true}) +;;=> ["SELECT [id] FROM [table]"] +``` + +## Format Options + +In addition to the `:quoted` and `:dialect` options described above, +`format` also accepts `:inline` and `:params`. + +The `:params` option was mentioned above and is used to specify +the values of named parameters in the DSL. + +The `:inline` option suppresses the generation of parameters in +the SQL string and instead tries to inline all the values directly +into the SQL string. The behavior is as if each value in the DSL +was wrapped in `[:inline `..`]`: + +* `nil` becomes the SQL value `NULL`, +* Clojure strings become inline SQL strings with single quotes (so `"foo"` becomes `'foo'`), +* keywords and symbols become SQL keywords (uppercase, with `-` replaced by a space), +* everything else is just turned into a string (by calling `str`) and added to the SQL string. + ## Reference Documentation The full list of supported SQL clauses is documented in the [docs/clause-reference.md](Clause Reference). The full list +of operators supported (as prefix-form "functions") is +documented in the [docs/operator-reference.md](Operator Reference) +section. The full list of "special syntax" functions is documented in the [docs/special-syntax.md](Special Syntax) section. The best documentation for the helper functions is the