### REPL-Driven Development Setup Source: https://github.com/seancorfield/honeysql/blob/develop/DEVELOPMENT.md Initialize a REPL session for interactive development by requiring necessary namespaces. ```clojure ;; Start by requiring the namespace (require '[honey.sql :as sql]) (require '[honey.sql.pg-ops :as pg]) ``` -------------------------------- ### Function Documentation Example Source: https://github.com/seancorfield/honeysql/blob/develop/DEVELOPMENT.md Example of a docstring for a public function, explaining its purpose, usage, and generated SQL. ```clojure (def => "The => operator for PostgreSQL named parameters in function calls. Used in function calls like: [:make_interval [:=> :secs 10]] Generates SQL: MAKE_INTERVAL(secs => ?)" :=>) ``` -------------------------------- ### Documentation Example Structure Source: https://github.com/seancorfield/honeysql/blob/develop/DEVELOPMENT.md Illustrates the recommended structure for documenting new features in PostgreSQL-specific documentation. ```markdown ## Feature Name Brief description of what it does and why it's useful. ```clojure user=> (require '[honey.sql.pg-ops :refer [=>]]) nil user=> (sql/format {:select [[[:simple_example]]}}) ["SELECT ..."] user=> (sql/format {:select [[[:complex_example]]}}) ["SELECT ..."] ``` Explanation of when to use this feature. ``` -------------------------------- ### Run Documentation Tests Source: https://github.com/seancorfield/honeysql/blob/develop/DEVELOPMENT.md Validate all code examples within the documentation files. ```bash clojure -T:build run-doc-tests ``` -------------------------------- ### HoneySQL 1.x Basic Usage Example Source: https://github.com/seancorfield/honeysql/blob/develop/doc/differences-from-1-x.md Demonstrates basic SQL formatting using HoneySQL 1.x's format function with select and where clauses. ```clojure (sql/format {:select [:*] :from [:table] :where [:= :id 1]}) ;;=> ["SELECT * FROM table WHERE id = ?" 1] ``` -------------------------------- ### HoneySQL 1.x Quoting Example Source: https://github.com/seancorfield/honeysql/blob/develop/doc/differences-from-1-x.md Shows how to apply specific quoting rules, like MySQL, using the format function in HoneySQL 1.x. ```clojure (sql/format {:select [:*] :from [:table] :where [:= :id 1]} :quoting :mysql) ;;=> ["SELECT FROM `table` WHERE `id` = ?" 1] ``` -------------------------------- ### Example Commit Message Source: https://github.com/seancorfield/honeysql/blob/develop/DEVELOPMENT.md A practical example of a commit message following the specified structure. ```text Add PostgreSQL => named parameter operator - Add operator definition and registration in pg-ops namespace - Include comprehensive tests for single and multiple parameters - Add documentation section with real PostgreSQL examples - All tests pass including documentation validation Addresses #582 ``` -------------------------------- ### Test Coverage Example Structure Source: https://github.com/seancorfield/honeysql/blob/develop/DEVELOPMENT.md An example structure for organizing tests to ensure comprehensive coverage, including basic, edge, integration, and error cases. ```clojure (testing "named parameter operator" (testing "single parameter" (is (= [...] (sql/format [...])))) (testing "multiple parameters" (is (= [...] (sql/format [...])))) (testing "with symbol reference" (is (= [...] (sql/format [...])))) (testing "real postgresql functions" (is (= [...] (sql/format [...]))))) ``` -------------------------------- ### HoneySQL 2.x Dialect Example Source: https://github.com/seancorfield/honeysql/blob/develop/doc/differences-from-1-x.md Shows how to specify a SQL dialect, like MySQL, using the options map in HoneySQL 2.x's format function. ```clojure (sql/format {:select [:*] :from [:table] :where [:= :id 1]} {:dialect :mysql}) ;;=> ["SELECT FROM `table` WHERE `id` = ?" 1] ``` -------------------------------- ### Execute Formatted SQL with next.jdbc Source: https://github.com/seancorfield/honeysql/blob/develop/README.md Example of executing a HoneySQL-generated parameterized query using the next.jdbc library. Ensure next.jdbc is added as a project dependency. ```clojure (jdbc/execute! conn (sql/format sqlmap)) ``` -------------------------------- ### NRQL Quoting Example Source: https://github.com/seancorfield/honeysql/blob/develop/doc/nrql.md Demonstrates how HoneySQL handles quoting for NRQL identifiers using backticks. ```clojure :foo/bar.baz ;;=> `foo/bar.baz` ``` -------------------------------- ### Basic Function Call with Vector Syntax Source: https://github.com/seancorfield/honeysql/blob/develop/README.md Demonstrates a basic function call using vector syntax for date manipulation. This example might be dialect-specific (e.g., MySQL). ```clojure (-> (select :*) (from :foo) (where [:> :date_created [:date_add [:now] [:interval 24 :hours]]]) (sql/format)) => ["SELECT * FROM foo WHERE date_created > DATE_ADD(NOW(), INTERVAL ? HOURS)" 24] ``` -------------------------------- ### :using Clause Example Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md The :using clause is intended for simple joins, often used with :delete-from. ```clojure user=> (sql/format {:delete-from :table1 :using [:table2 :table3] :where [:exists {:select [:1] :from [:table4] :where [:and [:= :table4.id :table1.id] [:= :table4.id :table2.id] [:= :table4.id :table3.id]]}]} ) ["DELETE FROM table1 USING table2, table3 WHERE EXISTS (SELECT 1 FROM table4 WHERE (table4.id = table1.id) AND (table4.id = table2.id) AND (table4.id = table3.id)) "] ``` -------------------------------- ### Named SQL Parameters with Keyword/Symbol Source: https://github.com/seancorfield/honeysql/blob/develop/doc/getting-started.md Illustrates using a keyword or symbol starting with '?' for named parameters, supplied via the :params option in format. ```clojure (sql/format {:select [:*] :from [:table] :where [:= :a :?x]} {:params {:x 42}}) ;;=> ["SELECT * FROM table WHERE a = ?" 42] ``` -------------------------------- ### Conditional Column Selection and WHERE Clauses Source: https://github.com/seancorfield/honeysql/blob/develop/README.md An example showing how to conditionally add columns to the `select` clause and conditions to the `where` clause using `cond->`. ```clojure (-> (select :a [:b :bar]) (cond-> need-c (select :c) x-val (select [:d :x])) (from [:foo :quux]) (where [:= :quux.a 1] [:< :bar 100]) (cond-> x-val (where [:> :x x-val])) sql/format) ``` -------------------------------- ### JOIN with Database-Specific Hints and Table Aliases Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md An example of adding database-specific hints to a join clause when both the table and its alias are specified. Metadata is applied to the table vector. ```clojure user=> (sql/format {:select [:col] :from [[:table :t]] :join [^:nolock [:extra :x] [:= :t.extra_id :x.id]] :where [:= :id 9]}) ``` -------------------------------- ### Replacing a Clause Using Dissoc Source: https://github.com/seancorfield/honeysql/blob/develop/README.md Demonstrates how to replace an existing SQL clause by first removing it with `dissoc` and then adding a new one. This example replaces the `select` and `where` clauses and formats the SQL. ```clojure (-> sqlmap (dissoc :select) (select :*) (where [:> :b 10]) sql/format) => ["SELECT * FROM foo WHERE (foo.a = ?) AND (b > ?)" "baz" 10] ``` -------------------------------- ### PostGIS Function Call with HoneySQL Source: https://github.com/seancorfield/honeysql/blob/develop/README.md Example of constructing a SQL INSERT statement with PostGIS functions like ST_SetSRID and ST_MakePoint using HoneySQL's DSL. ```clojure (-> (insert-into :sample) (values [{:location [:ST_SetSRID [:ST_MakePoint 0.291 32.621] [:cast 4325 :integer]]}]) (sql/format {:pretty true})) => [" INSERT INTO sample (location) VALUES (ST_SETSRID(ST_MAKEPOINT(?, ?), CAST(? AS INTEGER))) " 0.291 32.621 4325] ``` -------------------------------- ### Embedding Dynamic SQL String with :raw Source: https://github.com/seancorfield/honeysql/blob/develop/README.md Shows how to embed a dynamically constructed SQL string using :raw, combining string concatenation and values. This example embeds a time-based condition. ```clojure (-> (select :*) (from :foo) (where [:< :expired_at [:raw ["now() - '" 5 " seconds'"]]]) (sql/format)) => ["SELECT * FROM foo WHERE expired_at < now() - '5 seconds'"] ``` -------------------------------- ### SQL Formatting with :window and :over Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Demonstrates formatting SQL queries with window functions, including PARTITION BY and ORDER BY clauses, using Honeysql's map-based syntax. ```clojure user=> (sql/format {:select [:id [[:over [[:avg :salary] {:partition-by [:department] :order-by [:designation]} :Average] [[:max :salary] :w :MaxSalary]]]] :from [:employee] :window [:w {:partition-by [:department]}]} {:pretty true}) ``` -------------------------------- ### SQL Formatting with Helper Functions Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Illustrates using Honeysql's helper functions (select, over, partition-by, order-by, from, window) for a more readable construction of SQL queries with window functions. ```clojure user=> (sql/format (-> (select :id (over [[:avg :salary] (-> (partition-by :department) (order-by :designation)) :Average] [[:max :salary] :w :MaxSalary])) (from :employee) (window :w (partition-by :department))) {:pretty true}) ``` -------------------------------- ### Basic SQL Clause Construction Source: https://github.com/seancorfield/honeysql/blob/develop/README.md Demonstrates building a simple SQL query using `select`, `from`, and `where` helpers. The output shows the resulting data structure DSL. ```clojure (-> (select :a :b :c) (from :foo) (where [:= :foo.a "baz"])) => {:select [:a :b :c] :from [:foo] :where [:= :foo.a "baz"]} ``` -------------------------------- ### Multiple Window Clauses with Helper Functions Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Demonstrates defining multiple named windows ('w' and 'x') using Honeysql's helper functions for constructing complex SQL queries. ```clojure user=> (sql/format (-> (select :id (over [[:avg :salary] (-> (partition-by :department) (order-by :designation)) :Average] [[:max :salary] :w :MaxSalary])) (from :employee) (window :w (partition-by :department)) (window :x (partition-by :salary))) {:pretty true}) ``` -------------------------------- ### Syntax Validation: Correct Brackets Source: https://github.com/seancorfield/honeysql/blob/develop/DEVELOPMENT.md Example of correct Clojure syntax with properly balanced brackets for a HoneySQL format call. ```clojure ;; CORRECT - properly balanced (sql/format {:select [[[:make_interval [:=> :secs 10]]]]}) ``` -------------------------------- ### Syntax Validation: Missing Brackets Source: https://github.com/seancorfield/honeysql/blob/develop/DEVELOPMENT.md Example of incorrect Clojure syntax due to missing closing brackets in a HoneySQL format call. ```clojure ;; WRONG - missing closing brackets (sql/format {:select [[[:make_interval [:=> :secs 10]]]}) ``` -------------------------------- ### Named SQL Parameters with :param Syntax Source: https://github.com/seancorfield/honeysql/blob/develop/doc/getting-started.md Demonstrates using the :param special syntax for named parameters, also supplied via the :params option in format. ```clojure (sql/format {:select [:*] :from [:table] :where [:= :a [:param :x]]} {:params {:x 42}}) ;;=> ["SELECT * FROM table WHERE a = ?" 42] ``` -------------------------------- ### Upsert with WHERE clause on ON CONFLICT and DO UPDATE SET Source: https://github.com/seancorfield/honeysql/blob/develop/doc/postgresql.md Implement an upsert with conditional logic. This example includes a WHERE clause on the `ON CONFLICT` and `DO UPDATE SET` clauses. ```clojure user=> (-> (insert-into :user) (values [{:phone "5555555" :name "John"}]) (on-conflict :phone (where [:<> :phone nil])) (do-update-set :phone :name (where [:= :user.active false])) (sql/format {:pretty true})) ``` -------------------------------- ### Basic CREATE TABLE with Columns Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Defines a simple table with integer, varchar, and float columns. Use this for standard table creation. ```clojure user=> (sql/format {:create-table :fruit :with-columns [[:id :int [:not nil]] [:name [:varchar 32] [:not nil]] [:cost :float :null]]}) ["CREATE TABLE fruit (id INT NOT NULL, name VARCHAR(32) NOT NULL, cost FLOAT NULL)"] ``` -------------------------------- ### Multiple Window Definitions in SQL Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Shows how to define and use multiple named windows (e.g., 'w' and 'x') within a single SQL query using Honeysql. ```clojure user=> (sql/format {:select [:id [[:over [[:avg :salary] {:partition-by [:department] :order-by [:designation]} :Average] [[:max :salary] :w :MaxSalary]]]] :from [:employee] :window [:w {:partition-by [:department]}] :x {:partition-by [:salary]}}] {:pretty true}) ``` -------------------------------- ### Numbered Named SQL Parameters with Keyword/Symbol Source: https://github.com/seancorfield/honeysql/blob/develop/doc/getting-started.md Shows numbered placeholders with named parameters identified by a keyword/symbol starting with '?', when :numbered true is used. ```clojure (sql/format {:select [:*] :from [:table] :where [:= :a :?x]} {:params {:x 42} :numbered true}) ;;=> ["SELECT * FROM table WHERE a = $1" 42] ``` -------------------------------- ### Building Queries with Functional Helpers Source: https://github.com/seancorfield/honeysql/blob/develop/doc/getting-started.md Demonstrates constructing SQL queries using functional helpers from honey.sql.helpers, including select, from, and where clauses. ```clojure (require '[honey.sql :as sql] '[honey.sql.helpers :refer [select from where]]) (-> (select :t/id [:name :item]) (from [:table :t]) (where [:= :id 1]) (sql/format)) ;;=> ["SELECT t.id, name AS item FROM table AS t WHERE id = ?" 1] ``` -------------------------------- ### Run Full CI Pipeline Source: https://github.com/seancorfield/honeysql/blob/develop/DEVELOPMENT.md Execute the comprehensive CI pipeline for thorough testing. ```bash clojure -T:build ci ``` -------------------------------- ### Registering a New Function Formatter (Basic) Source: https://github.com/seancorfield/honeysql/blob/develop/doc/extending-honeysql.md Register a new function syntax with `sql/register-fn!` and a basic formatter function. The formatter receives the function name and arguments, returning a SQL string and parameters. ```clojure (sql/register-fn! :foo (fn [f args] ..)) (sql/format {:select [:*], :from [:table], :where [:foo 1 2 3]}) ``` ```clojure (sql/register-fn! :foo (fn [f args] ["FOO(?)" (first args)])) (sql/format {:select [:*], :from [:table], :where [:foo 1 2 3]}) ;; produces: ;;=> ["SELECT * FROM table WHERE FOO(?)" 1] ``` -------------------------------- ### Merging Repeated Clauses Source: https://github.com/seancorfield/honeysql/blob/develop/README.md Illustrates how repeated clauses are merged into existing ones when using helper functions. This example adds a column to an existing select clause. ```clojure (-> sqlmap (select :d)) => {:from [:foo], :where [:= :foo.a "baz"], :select [:a :b :c :d]} ``` -------------------------------- ### Aliasing Columns and Tables Source: https://github.com/seancorfield/honeysql/blob/develop/README.md Demonstrates how to alias columns and tables using vector pairs within the `select` and `from` helpers. The output includes the formatted SQL and parameters. ```clojure (-> (select :a [:b :bar] :c [:d :x]) (from [:foo :quux]) (where [:= :quux.a 1] [:< :bar 100]) sql/format) => ["SELECT a, b AS bar, c, d AS x FROM foo AS quux WHERE (quux.a = ?) AND (bar < ?)" 1 100] ``` -------------------------------- ### CREATE TABLE with Conditional and Keywords Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Demonstrates creating a table with conditional logic (IF NOT EXISTS) and custom SQL keywords preceding the table name. Useful for dynamic table creation or specific SQL dialects. ```clojure user=> (sql/format {:create-table [:my :fancy :fruit :if-not-exists] :with-columns [[:id :int [:not nil]] [:name [:varchar 32] [:not nil]] [:cost :float :null]]}) ["CREATE MY FANCY TABLE IF NOT EXISTS fruit (id INT NOT NULL, name VARCHAR(32) NOT NULL, cost FLOAT NULL)"] ``` -------------------------------- ### Render CONSTRAINT, DEFAULT, and REFERENCES Source: https://github.com/seancorfield/honeysql/blob/develop/doc/special-syntax.md These descriptors render as SQL keywords. With one argument, they render as keyword followed by the argument. With multiple arguments, they render as keyword followed by the first argument and then a regular argument list. ```clojure [:default] ;=> DEFAULT ``` ```clojure [:default 42] ;=> DEFAULT 42 ``` ```clojure [:default "str"] ;=> DEFAULT 'str' ``` ```clojure [:constraint :name] ;=> CONSTRAINT name ``` ```clojure [:references :foo :bar] ;=> REFERENCES foo(bar) ``` -------------------------------- ### Run Unit Tests Source: https://github.com/seancorfield/honeysql/blob/develop/DEVELOPMENT.md Execute the unit test suite for HoneySQL. ```bash clojure -X:test ``` -------------------------------- ### Formatting Queries with Different Dialects Source: https://github.com/seancorfield/honeysql/blob/develop/doc/extending-honeysql.md Demonstrates how to format a simple SQL query using both the default :ansi dialect and a custom registered dialect (::ANSI). This highlights the effect of the custom dialect's quoting and casing rules. ```clojure (sql/format {:select :foo :from :bar} {:dialect :ansi}) ;;=> ["SELECT \"foo\" FROM \"bar\""] (sql/format {:select :foo :from :bar} {:dialect ::ANSI}) ;;=> ["SELECT \"FOO\" FROM \"BAR\""] ``` -------------------------------- ### Create Basic Index Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Use `:create-index` to create an index. It accepts an index specification and column specification. Some databases treat this as an alias for `:alter-table` `:add-index`. ```clojure user=> (sql/format {:create-index [:my-idx [:fruit :appearance]]}) ["CREATE INDEX my_idx ON fruit (appearance)"] ``` ```clojure user=> (sql/format {:create-index [[:unique :another-idx] [:fruit :color :appearance]]}) ["CREATE UNIQUE INDEX another_idx ON fruit (color, appearance)"] ``` -------------------------------- ### Formatting Array Constructor (Pre-2.5.1091) Source: https://github.com/seancorfield/honeysql/blob/develop/doc/postgresql.md Illustrates the workaround using HoneySQL's 'as-is' function syntax for formatting ARRAY constructors from subqueries in versions prior to 2.5.1091. ```clojure (sql/format {:select [[[:'ARRAY {:select :oid :from :pg_proc :where [:like :proname [:inline "bytea%"]]}]]]}) ``` -------------------------------- ### Using :join-by with Helper Functions Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Shows an alternative way to use :join-by by employing helper functions for join clauses, achieving the same result as the direct keyword/clause sequence. ```clojure user=> (sql/format (-> (select :t.ref :pp.code) (from [:transaction :t]) (join-by (left-join [:paypal-tx :pp] [:using :id]) (join [:logtransaction :log] [:= :t.id :log.id])) (where := "settled" :pp.status)) {:pretty true}) ``` -------------------------------- ### Window Functions with Nil/Empty Over Clause Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Shows how to format SQL queries for window functions where the OVER clause is empty or nil, indicating a global window. ```clojure user=> (sql/format {:select [:id [[:over [[:avg :salary] {} :Average] [[:max :salary] nil :MaxSalary]]]] :from [:employee]}) ``` -------------------------------- ### Format SQL with alias Source: https://github.com/seancorfield/honeysql/blob/develop/doc/special-syntax.md Demonstrates how to use the :alias special syntax to format SQL statements, allowing for custom alias names in clauses like ORDER BY and GROUP BY. ```clojure (sql/format {:select [[:column-name "some-alias"]] :from :b :order-by [[[:alias "some-alias"]]]}) ;;=> ["SELECT column_name AS \"some-alias\" FROM b ORDER BY \"some-alias\" ASC"] ``` ```clojure (sql/format {:select [[:column-name :'some-alias']] :from :b :order-by [[[:alias :'some-alias]]}}) ;;=> ["SELECT column_name AS \"some-alias\" FROM b ORDER BY \"some-alias\" ASC"] ``` ```clojure (sql/format {:select [[:column-name "some-alias"]] :from :b :group-by [[:alias "some-alias"]]}) ;;=> ["SELECT column_name AS \"some-alias\" FROM b GROUP BY \"some-alias\"] ``` ```clojure (sql/format {:select [[:column-name "some-alias"]] :from :b :group-by [[:alias :'some-alias]]}) ;;=> ["SELECT column_name AS \"some-alias\" FROM b GROUP BY \"some-alias\"] ``` -------------------------------- ### Refer Specific Helpers for HoneySQL (ClojureScript) Source: https://github.com/seancorfield/honeysql/blob/develop/README.md This snippet demonstrates how to import HoneySQL and its helpers in a ClojureScript environment, where `:refer :all` is not recommended. It explicitly lists the helpers to be referred. ```clojure (refer-clojure :exclude '[filter for group-by into partition-by set update]) (require '[honey.sql :as sql] '[honey.sql.helpers :refer [select select-distinct from join left-join right-join where for group-by having union order-by limit offset values columns update insert-into set composite delete delete-from truncate] :as h] '[clojure.core :as c]) ``` -------------------------------- ### Set SQL Server Dialect Globally Source: https://github.com/seancorfield/honeysql/blob/develop/doc/getting-started.md Illustrates how to globally set the SQL dialect to SQL Server using `set-dialect!`. ```clojure (sql/set-dialect! :sqlserver) ``` -------------------------------- ### Format SQL with Named Parameters Source: https://github.com/seancorfield/honeysql/blob/develop/doc/options.md Demonstrates how to use the :params option to map named parameters to values for a SQL formatting call. This is useful for generating SQL with placeholders that are then filled with specific values. ```clojure (require '[honey.sql :as sql]) (-> {:select :* :from :table :where [:= :id :?id]} (sql/format {:params {:id 42}})) ;;=> ["SELECT * FROM table WHERE id = ?" 42] ``` ```clojure (-> '{select * from table where (= id ?id)} (sql/format {:params {:id 42}})) ;;=> ["SELECT * FROM table WHERE id = ?" 42] ``` -------------------------------- ### Bindable Parameter with Numbered Parameters Source: https://github.com/seancorfield/honeysql/blob/develop/README.md Illustrates using a '?' prefixed keyword for a bindable parameter and enabling numbered parameters for the output SQL. ```clojure ;; or with numbered parameters: (-> (select :id) (from :foo) (where [:= :a :?baz]) (sql/format {:params {:baz "BAZ"} :numbered true})) => ["SELECT id FROM foo WHERE a = $1" "BAZ"] ``` -------------------------------- ### Numbered Named SQL Parameters with :param Syntax Source: https://github.com/seancorfield/honeysql/blob/develop/doc/getting-started.md Illustrates numbered placeholders with named parameters using the :param syntax, when :numbered true is used. ```clojure (sql/format {:select [:*] :from [:table] :where [:= :a [:param :x]]} {:params {:x 42} :numbered true}) ;;=> ["SELECT * FROM table WHERE a = $1" 42] ``` -------------------------------- ### Basic SELECT and Omitted SELECT Source: https://github.com/seancorfield/honeysql/blob/develop/doc/xtdb.md Demonstrates how to format a basic SELECT statement and how omitting the :select clause implies SELECT * in XTDB. ```clojure (sql/format '{select * from foo where (= status "active")}) ["SELECT * FROM foo WHERE status = ?" "active"] ``` ```clojure (sql/format '{from foo where (= status "active")}) ["FROM foo WHERE status = ?" "active"] ``` -------------------------------- ### JOIN with Database-Specific Hints (SQL Server NOLOCK) Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Shows how to add database-specific hints, like SQL Server's WITH (NOLOCK), to a join clause by using metadata on the table expression. The table name must be a vector when using metadata. ```clojure user=> (sql/format {:select [:col] :from [:table] :join [^:nolock [:extra] [:= :table.extra_id :extra.id]] :where [:= :id 9]}) ``` -------------------------------- ### CREATE TABLE with Inline Constraints and Pretty Printing Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Illustrates defining inline column constraints (like CHECK) and table constraints, with pretty-printed output. Useful for complex table definitions with specific validation rules. ```clojure user=> (-> '{create-table quux with-columns ((a integer (constraint a_pos) (check (> a 0))) (b integer) ((constraint a_bigger) (check (< b a))))} (sql/format {:pretty true})) [" CREATE TABLE quux (a INTEGER CONSTRAINT a_pos CHECK(a > 0), b INTEGER, CONSTRAINT a_bigger CHECK(b < a)) "] ``` -------------------------------- ### SQL Operators and Special Syntax Source: https://github.com/seancorfield/honeysql/blob/develop/doc/getting-started.md Demonstrates common SQL operators like '=' and '+', and special syntax like ':inline' for inlining values and ':now' for functions. ```clojure [:= :a 42] ``` ```clojure [:+ 42 :a :b] ``` ```clojure [:= :x [:inline "foo"]] ``` ```clojure [:now] ``` ```clojure [:count :*] ``` ```clojure [:or [:<> :name nil] [:= :status-id 0]] ``` -------------------------------- ### Interactive SQL Formatting in REPL Source: https://github.com/seancorfield/honeysql/blob/develop/DEVELOPMENT.md Test SQL formatting interactively in the REPL using HoneySQL. ```clojure ;; Test your changes interactively (sql/format {:select [[[:make_interval [:=> :secs 10]]]]}) ;; => ["SELECT MAKE_INTERVAL(secs => ?)" 10] ``` -------------------------------- ### Format SQL JSON navigation with :at Source: https://github.com/seancorfield/honeysql/blob/develop/doc/special-syntax.md Illustrates using the :at special syntax for JSON navigation in SQL, supporting field access and array indexing. Handles parameterization for array indices. ```clojure (sql/format {:select [[[:at :col :field1 :field2]]}}) ["SELECT col.field1.field2"] ``` ```clojure (sql/format {:select [[[:at :table.col 0 :field]]}}) ["SELECT table.col[0].field"] ``` ```clojure (sql/format {:select [[[:at :col [:lift 0] :field]]}}) ["SELECT col[?].field" 0] ``` -------------------------------- ### SELECT Clause with Expressions and Aliases Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Shows how to format SELECT clauses with simple columns, expressions without aliases, and expressions with aliases. Expressions without aliases are double-nested. ```clojure user=> (sql/format '{select (id, ((* cost 2)), (event status)) from (table)}) ["SELECT id, cost * ?, event AS status FROM table" 2] ``` ```clojure user=> (sql/format {:select [:id, [[:* :cost 2] :total], [:event :status]] :from [:table]}) ["SELECT id, cost * ? AS total, event AS status FROM table" 2] ``` -------------------------------- ### SELECT Clause Formatting Source: https://github.com/seancorfield/honeysql/blob/develop/doc/getting-started.md Illustrates various ways to format SELECT clauses, including simple columns, aliased columns, and function calls using both nested vectors and the '%' prefix. ```clojure (sql/format {:select [:a]}) ``` ```clojure (sql/format {:select [[:a :b]]}) ``` ```clojure (sql/format {:select [[[:a :b]]]}) ``` ```clojure (sql/format {:select [:%a.b]}) ``` ```clojure (sql/format {:select [[[:a :b] :c]]}) ``` ```clojure (sql/format {:select [[:%a.b :c]]}) ``` ```clojure (sql/format {:select [:x [:y :d] [[:z :e]] [[:z :f] :g]]}) ``` ```clojure (sql/format {:select [:x [:y :d] [:%z.e] [:%z.f :g]]}) ``` ```clojure (sql/format {:select [:x [:y :d] :%z.e [:%z.f :g]]}) ``` -------------------------------- ### Insert with Map Values and Missing Columns (DEFAULT specified) Source: https://github.com/seancorfield/honeysql/blob/develop/README.md Shows how to use the `:values-default-columns` option to specify that missing columns should use the SQL DEFAULT keyword instead of NULL. ```clojure (-> (insert-into :properties) (values [{:name "John" :surname "Smith" :age 34} {:name "Andrew" :age 12} {:name "Jane" :surname "Daniels"}]) (sql/format {:pretty true :values-default-columns #{:age}})) ``` -------------------------------- ### Formatting a Complex Query with Parameters Source: https://github.com/seancorfield/honeysql/blob/develop/README.md Renders the complex query map into SQL, demonstrating parameter substitution for both named and numbered parameters, and pretty-printing the output. ```clojure (sql/format big-complicated-map {:params {:param1 "gabba" :param2 2} :pretty true}) => [" SELECT DISTINCT f.*, b.baz, c.quux, b.bla AS \"bla-bla\", NOW(), @x := 10 FROM foo AS f, baz AS b INNER JOIN draq ON f.b = draq.x INNER JOIN eldr ON f.e = eldr.t LEFT JOIN clod AS c ON f.a = c.d RIGHT JOIN bock ON bock.z = c.e WHERE ((f.a = ?) AND (b.baz <> ?)) OR ((? < ?) AND (? < ?)) OR (f.e IN (?, ?, ?)) OR f.e BETWEEN ? AND ? GROUP BY f.a, c.e HAVING ? < f.e ORDER BY b.baz DESC, c.quux ASC, f.a NULLS FIRST LIMIT ? OFFSET ? " "bort" "gabba" 1 2 2 3 1 2 3 10 20 0 50 10] ;; with numbered parameters: (sql/format big-complicated-map {:params {:param1 "gabba" :param2 2} :pretty true :numbered true}) => [" SELECT DISTINCT f.*, b.baz, c.quux, b.bla AS \"bla-bla\", NOW(), @x := 10 FROM foo AS f, baz AS b INNER JOIN draq ON f.b = draq.x INNER JOIN eldr ON f.e = eldr.t LEFT JOIN clod AS c ON f.a = c.d RIGHT JOIN bock ON bock.z = c.e WHERE ((f.a = $1) AND (b.baz <> $2)) OR (($3 < $4) AND ($5 < $6)) OR (f.e IN ($7, $8, $9)) OR f.e BETWEEN $10 AND $11 GROUP BY f.a, c.e HAVING $12 < f.e ORDER BY b.baz DESC, c.quux ASC, f.a NULLS FIRST LIMIT $13 OFFSET $14 " "bort" "gabba" 1 2 2 3 1 2 3 10 20 0 50 10] ``` -------------------------------- ### UNION Clause Formatting Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Demonstrates basic UNION clause formatting. For databases like BigQuery that require parenthesized clauses, use the :nest option. ```clojure user=> (sql/format '{union [{select (id,status) from (table-a)} {select (id,(event status) from (table-b))}]}) ["SELECT id, status FROM table_a UNION SELECT id, event AS status, from, table_b"] ``` ```clojure ;; BigQuery requires UNION clauses be parenthesized: user=> (sql/format '{union [{:nest {select (id,status) from (table-a)}} {:nest {select (id,(event status) from (table-b))}}]}) ["(SELECT id, status FROM table_a) UNION (SELECT id, event AS status, from, table_b)"] ``` -------------------------------- ### SQL Entity Generation with Quoting Source: https://github.com/seancorfield/honeysql/blob/develop/doc/general-reference.md Demonstrates how HoneySQL formats unqualified keywords/symbols as quoted SQL entities when quoting is enabled. ```clojure (require '[honey.sql :as sql]) (sql/format {:select :foo-bar} {:quoted true}) ;;=> ["SELECT \"foo-bar\""] (sql/format {:select :foo-bar} {:dialect :mysql}) ;;=> ["SELECT `foo-bar`"] ``` -------------------------------- ### Helper Functions for Nil/Empty Over Clause Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Illustrates using Honeysql's helper functions to construct SQL queries with window functions and empty/nil OVER clauses. ```clojure user=> (sql/format (-> (select :id (over [[:avg :salary] {} :Average] [[:max :salary] nil :MaxSalary])) (from :employee))) ``` -------------------------------- ### SQL Entity Generation for Strings in Specific Contexts Source: https://github.com/seancorfield/honeysql/blob/develop/doc/general-reference.md Shows how strings are treated as SQL entities in contexts like `:set`, ensuring quoting and preserving dashes/slashes, regardless of dialect or quoting settings. ```clojure (sql/format {:update :table :set {"foo-bar" 1 "baz/quux" 2}}) ;;=> ["UPDATE table SET \"foo-bar\" = ?, \"baz/quux\" = ?" 1 2] (sql/format {:update :table :set {"foo-bar" 1 "baz/quux" 2}} {:quoted true}) ;;=> ["UPDATE \"table\" SET \"foo-bar\" = ?, \"baz/quux\" = ?" 1 2] (sql/format {:update :table :set {"foo-bar" 1 "baz/quux" 2}} {:dialect :mysql}) ;;=> ["UPDATE `table` SET `foo-bar` = ?, `baz/quux` = ?" 1 2] (sql/format {:update :table :set {"foo-bar" 1 "baz/quux" 2}} {:dialect :sqlserver :quoted false}) ;;=> ["UPDATE table SET [foo-bar] = ?, [baz/quux] = ?" 1 2] ``` -------------------------------- ### Render FOREIGN KEY and PRIMARY KEY Source: https://github.com/seancorfield/honeysql/blob/develop/doc/special-syntax.md These descriptors render as SQL keywords when no arguments are provided. With arguments, they render as keywords followed by a list of identifiers. ```clojure [:foreign-key] ;=> FOREIGN KEY ``` ```clojure [:primary-key] ;=> PRIMARY KEY ``` ```clojure [:foreign-key :a] ;=> FOREIGN KEY(a) ``` ```clojure [:primary-key :x :y] ;=> PRIMARY KEY(x, y) ``` -------------------------------- ### SQL Entity Generation with Qualified Names (Namespace/Name) Source: https://github.com/seancorfield/honeysql/blob/develop/doc/general-reference.md Explains how qualified keywords/symbols are formatted, noting that dashes in the namespace are converted to underscores even with quoting. ```clojure (sql/format {:select :foo-bar/baz-quux} {:quoted true}) ;;=> ["SELECT \"foo_bar\".\"baz-quux\"] ; _ in table, - in column (sql/format {:select :foo-bar/baz-quux} {:dialect :mysql}) ;;=> ["SELECT `foo_bar`.`baz-quux`"] ; _ in table, - in column (sql/format {:select :foo-bar/baz-quux}) ;;=> ["SELECT foo_bar.baz_quux"] ; _ in table and _ in column (sql/format {:select :foo-bar/baz-quux} {:dialect :mysql :quoted false}) ;;=> ["SELECT foo_bar.baz_quux"] ; _ in table and _ in column ``` -------------------------------- ### Using :join-by with Alternating Join Operations Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Demonstrates constructing multiple JOIN operations in a specific order using the :join-by clause. This method accepts a sequence of alternating join operation keywords and their corresponding clauses. ```clojure user=> (sql/format {:select [:t.ref :pp.code] :from [[:transaction :t]] :join-by [:left [[:paypal-tx :pp] [:using :id]] :join [[:logtransaction :log] [:= :t.id :log.id]]] :where [:= "settled" :pp.status]} {:pretty true}) ``` -------------------------------- ### Numbered SQL Parameters Source: https://github.com/seancorfield/honeysql/blob/develop/doc/getting-started.md Shows how to use the :numbered true option with format to generate numbered placeholders ($1, $2, etc.) instead of positional ones. ```clojure ;; with :numbered true option: [:between :size 10 20] ;=> "size BETWEEN $1 AND $2" with parameters 10 and 20 ``` -------------------------------- ### Bindable Parameter with Pure Data DSL Source: https://github.com/seancorfield/honeysql/blob/develop/README.md Demonstrates using a '?' prefixed keyword for a bindable parameter within the pure data DSL structure. ```clojure ;; or as pure data DSL: (-> {:select [:id], :from [:foo], :where [:= :a :?baz]} (sql/format {:params {:baz "BAZ"}})) => ["SELECT id FROM foo WHERE a = ?" "BAZ"] ``` -------------------------------- ### Default Quoting Strategy with SQL Server Dialect Source: https://github.com/seancorfield/honeysql/blob/develop/doc/getting-started.md Demonstrates using the default quoting strategy (`:quoted nil`) with the SQL Server dialect, where only unusual entities are quoted and standard entities are not. ```clojure (sql/format '{select (id, iffy##field ) from (table)} {:dialect :sqlserver :quoted nil}) ``` -------------------------------- ### Caching SQL Generation with HoneySQL Source: https://github.com/seancorfield/honeysql/blob/develop/doc/general-reference.md Demonstrates how different literal parameter values result in distinct cache entries, while named parameters with the same name but different values result in a single cache entry. ```clojure ;; these are two different cache entries: (sql/format {:select :* :from :table :where [:= :id 1]} {:cache my-cache}) (sql/format {:select :* :from :table :where [:= :id 2]} {:cache my-cache}) ``` ```clojure ;; these are the same cache entry: (sql/format {:select :* :from :table :where [:= :id :?id]} {:cache my-cache :params {:id 1}}) (sql/format {:select :* :from :table :where [:= :id :?id]} {:cache my-cache :params {:id 2}}) ``` -------------------------------- ### Generate SELECT TOP Clause with Percent and With Ties Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Use `select-top` with a limit expression including `:percent` and `:with-ties` qualifiers for MS SQL Server. ```clojure user=> (sql/format {:select-top [[10 :percent :with-ties] :foo :baz] :from :bar :order-by [:quux]}) ["SELECT TOP(?) PERCENT WITH TIES foo, baz FROM bar ORDER BY quux ASC" 10] ``` -------------------------------- ### SQL Entity Generation with Dots (Table.Column) Source: https://github.com/seancorfield/honeysql/blob/develop/doc/general-reference.md Illustrates how HoneySQL handles names with dots, splitting them into table and column, with variations based on quoting and dialect. ```clojure (sql/format {:select :foo-bar.baz-quux} {:quoted true}) ;;=> ["SELECT \"foo-bar\".\"baz-quux\"] (sql/format {:select :foo-bar.baz-quux} {:dialect :mysql}) ;;=> ["SELECT `foo-bar`.`baz-quux`"] (sql/format {:select :foo-bar.baz-quux}) ;;=> ["SELECT foo_bar.baz_quux"] (sql/format {:select :foo-bar.baz-quux} {:dialect :mysql :quoted false}) ;;=> ["SELECT foo_bar.baz_quux"] ``` -------------------------------- ### Offset and Fetch Pagination (ANSI SQL) Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Generates SQL with OFFSET and FETCH clauses, the ANSI-compliant standard for pagination. ```clojure user=> (sql/format {:select [:id :name] :from [:table] :offset 20 :fetch 10}) ["SELECT id, name FROM table OFFSET ? ROWS FETCH NEXT ? ROWS ONLY" 20 10] ``` -------------------------------- ### Format with MySQL Dialect Source: https://github.com/seancorfield/honeysql/blob/develop/doc/getting-started.md Shows how to format a query using the MySQL dialect, which applies backticks for quoting. ```clojure (sql/format '{select (id) from (table)} {:dialect :mysql}) ``` -------------------------------- ### Format SQL with Namespace-Qualified Keywords Source: https://github.com/seancorfield/honeysql/blob/develop/README.md Demonstrates how HoneySQL handles namespace-qualified keywords, converting them to table-qualified column names. This improves compatibility with libraries like next.jdbc. ```clojure (def q-sqlmap {:select [:foo/a :foo/b :foo/c] :from [:foo] :where [:= :foo/a "baz"]}) (sql/format q-sqlmap) => ["SELECT foo.a, foo.b, foo.c FROM foo WHERE foo.a = ?" "baz"] ``` ```clojure (-> '{select (foo/a, foo/b, foo/c) from (foo) where (= foo/a "baz")} (sql/format)) => ["SELECT foo.a, foo.b, foo.c FROM foo WHERE foo.a = ?" "baz"] ``` -------------------------------- ### Reset to ANSI Dialect Source: https://github.com/seancorfield/honeysql/blob/develop/doc/getting-started.md Illustrates how to reset the global dialect back to the default ANSI SQL mode. ```clojure (sql/set-dialect! :ansi) ``` -------------------------------- ### Formatting Array Constructor from Subquery Source: https://github.com/seancorfield/honeysql/blob/develop/doc/postgresql.md Shows how to format a PostgreSQL ARRAY constructor that takes a subquery as its argument, using HoneySQL's direct support. ```clojure (sql/format {:select [[[:array {:select :oid :from :pg_proc :where [:like :proname [:inline "bytea%"]]}]]]}) ``` -------------------------------- ### Using PostgreSQL Named Parameter Operator (=>) Source: https://github.com/seancorfield/honeysql/blob/develop/doc/postgresql.md Shows how to format PostgreSQL function calls with named parameters using the `=>` operator provided by `honey.sql.pg-ops`. ```clojure (require '[honey.sql.pg-ops :refer [=>]]) (sql/format {:select [[[:make-interval [:=> :secs 10]]]]}) ``` ```clojure (sql/format {:select [[[:make-interval [:=> :secs 10] [:=> :mins 5]]]]}) ``` ```clojure (sql/format {:select [[[:date-trunc [:=> :field "month"] [:=> :source "2023-06-15"]]]}) ``` -------------------------------- ### Format with Global MySQL Dialect and Quoting Source: https://github.com/seancorfield/honeysql/blob/develop/doc/getting-started.md Formats a query using the globally set MySQL dialect and quoting settings. ```clojure (sql/format '{select (id) from (table)}) ``` -------------------------------- ### Bindable Parameter with Named Parameter Source: https://github.com/seancorfield/honeysql/blob/develop/README.md Shows how to use a '?' prefixed keyword for a bindable parameter, mapping it to a named parameter in the format options. ```clojure (-> (select :id) (from :foo) (where [:= :a :?baz]) (sql/format {:params {:baz "BAZ"}})) => ["SELECT id FROM foo WHERE a = ?" "BAZ"] ``` -------------------------------- ### Refer Clojure Core Functions for HoneySQL (Clojure) Source: https://github.com/seancorfield/honeysql/blob/develop/README.md This snippet shows how to import HoneySQL and its helpers in a Clojure environment. It excludes certain clojure.core functions to avoid conflicts when using `:refer :all`. ```clojure (refer-clojure :exclude '[assert distinct filter for group-by into partition-by set update]) (require '[honey.sql :as sql] ;; CAUTION: this overwrites several clojure.core fns: ;; ;; distinct, filter, for, group-by, into, partition-by, set, and update ;; ;; you should generally only refer in the specific ;; helpers that you want to use! '[honey.sql.helpers :refer :all :as h] ;; so we can still get at clojure.core functions: '[clojure.core :as c]) ``` -------------------------------- ### Quoting Entity Names with MySQL Dialect Source: https://github.com/seancorfield/honeysql/blob/develop/README.md Demonstrates how to format SQL with entity names quoted for the MySQL dialect using the :dialect option. ```clojure (-> (select :foo.a) (from :foo) (where [:= :foo.a "baz"]) (sql/format {:dialect :mysql})) => ["SELECT `foo`.`a` FROM `foo` WHERE `foo`.`a` = ?" "baz"] ``` -------------------------------- ### Formatting Basic Array Expressions Source: https://github.com/seancorfield/honeysql/blob/develop/doc/postgresql.md Demonstrates how to format a simple SQL ARRAY expression with literal values using HoneySQL. ```clojure (sql/format {:select [[[:array [1 2 3]] :a]]}) ``` -------------------------------- ### Insert with Heterogeneous Values Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Demonstrates inserting rows with varying numbers of values. HoneySQL pads shorter rows with NULLs. ```clojure user=> (sql/format {:insert-into :table :values [[1 2] [2 3 4 5] [3 4 5]]}) ["INSERT INTO table VALUES (?, ?, NULL, NULL), (?, ?, ?, ?), (?, ?, ?, NULL)" 1 2 2 3 4 5 3 4 5] ``` ```clojure user=> (sql/format '{insert-into table values ({id 1 name "Sean"} {id 2} {name "Extra"})}) ["INSERT INTO table (id, name) VALUES (?, ?), (?, NULL), (NULL, ?)" 1 "Sean" 2 "Extra"] ``` ```clojure user=> (sql/format '{insert-into table values ({id 1 name "Sean"} {id 2} {name "Extra"})} {:values-default-columns #{'id}}) ["INSERT INTO table (id, name) VALUES (?, ?), (?, NULL), (DEFAULT, ?)" 1 "Sean" 2 "Extra"] ``` -------------------------------- ### Format with Quoting Enabled Source: https://github.com/seancorfield/honeysql/blob/develop/doc/getting-started.md Demonstrates how to format a query with explicit quoting enabled for all SQL entities, regardless of dialect. ```clojure (sql/format '{select (id) from (table)} {:quoted true}) ``` -------------------------------- ### SELECT Function Call Syntax Source: https://github.com/seancorfield/honeysql/blob/develop/doc/differences-from-1-x.md Demonstrates the new syntax for selecting function calls directly within a SELECT statement, avoiding the need for sql/call. ```clojure user=> (sql/format {:select [:a [:b :c] [[:d :e]] [[:f :g] :h]]}) ;; select a (column), b (aliased to c), d (fn call), f (fn call, aliased to h): ["SELECT a, b AS c, D(e), F(g) AS h"] ``` -------------------------------- ### Registering a New Function Formatter (Advanced) Source: https://github.com/seancorfield/honeysql/blob/develop/doc/extending-honeysql.md Register a new function with a custom formatter that utilizes `sql/sql-kw` for SQL keyword representation and `sql/format-expr` for argument formatting. ```clojure (defn- foo-formatter [f [x]] (let [[sql & params] (sql/format-expr x)] (into [(str (sql/sql-kw f) "(" sql ")")] params))) (sql/register-fn! :foo foo-formatter) (sql/format {:select [:*], :from [:table], :where [:foo [:+ :a 1]]}) ;; produces: ;;=> ["SELECT * FROM table WHERE FOO(a + ?)" 1] ``` -------------------------------- ### :from Clause with :use-index Hint Source: https://github.com/seancorfield/honeysql/blob/develop/doc/clause-reference.md Use the :use-index hint with metadata on a table vector to suggest specific indices for the query. ```clojure user=> (sql/format {:select [:col] :from [^{:use-index [:ix-name]} [:table]] :where [:= :name "steve"]}) ["SELECT col FROM table USE INDEX (ix_name) WHERE name = ?" "steve"] ```