https://github.com/fukamachi/sxql
An SQL generator for Common Lisp.
https://github.com/fukamachi/sxql
Last synced: about 1 year ago
JSON representation
An SQL generator for Common Lisp.
- Host: GitHub
- URL: https://github.com/fukamachi/sxql
- Owner: fukamachi
- License: bsd-3-clause
- Created: 2013-10-21T15:39:52.000Z (over 12 years ago)
- Default Branch: master
- Last Pushed: 2024-10-23T01:32:07.000Z (over 1 year ago)
- Last Synced: 2025-02-18T21:00:41.752Z (about 1 year ago)
- Language: Common Lisp
- Homepage:
- Size: 317 KB
- Stars: 369
- Watchers: 20
- Forks: 32
- Open Issues: 24
-
Metadata Files:
- Readme: README.markdown
- License: LICENSE
Awesome Lists containing this project
- awesome-cl - sxql - A DSL for generating SQL. [3-clause BSD][15]. (Expert Systems)
README
# SxQL - An SQL generator.
[](https://travis-ci.org/fukamachi/sxql)
## Usage
```common-lisp
(select (:id :name :sex)
(from (:as :person :p))
(where (:and (:>= :age 18)
(:< :age 65)))
(order-by (:desc :age)))
;=> #= 18) AND (age < 65)) ORDER BY age DESC>
(yield *)
;=> "SELECT id, name, sex FROM person AS p WHERE ((age >= ?) AND (age < ?)) ORDER BY age DESC"
; (18 65)
(sql-compile **)
;=> #= ?) AND (age < ?)) ORDER BY age DESC [18, 65]>
(union-queries * (select (:id :name :sex) (from '(:as animal a))))
;=> #= ?) AND (age < ?)) ORDER BY age DESC) UNION (SELECT id, name, sex FROM (animal AS a))>
(yield *)
;=> "(SELECT id, name, sex FROM (person AS p) WHERE ((age >= ?) AND (age < ?)) ORDER BY age DESC) UNION (SELECT id, name, sex FROM (animal AS a))"
; (18 65)
```
## SQL Statements
### select (field &body clauses)
Creates a SELECT query. It takes a field (or a list of fields) and SQL Clauses.
```common-lisp
(select ((:+ 1 1)))
;=> #
(select :name
(from :person)
(where (:> :age 20)))
;=> # 20)>
(select (:id :name)
(from (:as :person :p))
(left-join :person_config :on (:= :person.config_id :person_config.id))
(where (:and (:> :age 20)
(:<= :age 65)))
(order-by :age)
(limit 5))
;=> # 20) AND (age <= 65)) ORDER BY age LIMIT 5>
(select (:sex (:count :*)) (from :person) (group-by :sex))
;=> #
(select (:sex (:as (:count :*) :num))
(from :person)
(group-by :sex)
(order-by (:desc :num)))
;=> #
```
### insert-into (table &body clauses)
```common-lisp
(insert-into :person
(set= :sex "male"
:age 25
:name "Eitaro Fukamachi"))
;=> #
(insert-into :person
(:sex :age :name)
(list "male" 25 "Eitaro Fukamachi"))
;=> #
(insert-into :person
(:sex :age :name)
(list (list "male" 25 "Eitaro Fukamachi")
(list "female" 16 "Miku Hatsune")))
;=> #
(insert-into :users
(set= :name "Jack"
:jinbei-size "small")
(returning :id))
;=> #
(insert-into :person
(:id :name)
(select (:id :name)
(from :person_tmp)))
;=> #
```
### update (table &body clauses)
```common-lisp
(update :person
(set= :age 26)
(where (:like :name "Eitaro %")))
;=> #
```
### delete-from (table &body clauses)
```common-lisp
(delete-from :person
(where (:= :name "Eitaro Fukamachi")))
;=> #
```
### union-queies (&rest statements)
```common-lisp
(union-queries
(select (:name :birthday) (from :fulltime))
(select (:name :birthday) (from :parttime)))
;=> #
```
### union-all-queries (&rest statements)
```common-lisp
(union-all-queries
(select (:name :birthday) (from :fulltime))
(select (:name :birthday) (from :parttime)))
;=> #
```
### create-table (table column-definitions &body options)
```common-lisp
(create-table :enemy
((name :type 'string
:primary-key t)
(age :type 'integer
:not-null t)
(address :type 'text
:not-null nil)
(fatal_weakness :type 'text
:not-null t
:default "None")
(identifying_color :type '(:char 20)
:unique t)))
;=> #
(yield *)
;=> "CREATE TABLE enemy (name STRING PRIMARY KEY, age INTEGER NOT NULL, address TEXT, fatal_weakness TEXT NOT NULL DEFAULT ?, identifying_color CHAR(20) UNIQUE)"
; ("None")
(create-table (:enemy :if-not-exists t)
((name :type 'string
:primary-key t)
(age :type 'integer
:not-null t)
(address :type 'text
:not-null nil)
(fatal_weakness :type 'text
:not-null t
:default "None")
(identifying_color :type '(:char 20)
:unique t)))
;=> #
```
### drop-table (table &key if-exists)
```common-lisp
(drop-table :enemy)
;=> #
(drop-table :enemy :if-exists t)
;=> #
```
### alter-table (table &body clauses)
```common-lisp
(alter-table :tweet
(add-column :id :type 'bigint :primary-key t :auto-increment t :first t)
(add-column :updated_at :type 'timestamp))
;=> #
```
### create-index (index-name &key unique using on)
```common-lisp
(create-index "index_name"
:unique t
:using :btee
:on '(:table :column1 :column2))
;=> #
```
### drop-index (index-name &key if-exists on)
```common-lisp
(drop-index "index_name" :if-exists t :on :person)
;=> #
```
## SQL Clauses
### fields
```common-lisp
(fields :id)
;=> #
(fields (:count :id))
;=> #
(fields :id (:sum :amount))
;=> #
```
### from
```common-lisp
(from :person)
;=> #
(from :person :person_config)
;=> #
(from (select :* (from :person) (where (:= :is_active 1))))
;=> #
```
### where
```common-lisp
(where (:and (:> :age 20) (:<= :age 65)))
;=> # 20) AND (age <= 65))>
(yield *)
;=> "WHERE ((age > ?) AND (age <= ?))"
; (20 65)
```
### order-by
```common-lisp
(order-by :age)
;=> #
(order-by :age (:desc :id))
;=> #
; NIL
```
### group-by
```common-lisp
(group-by :sex)
;=> #
```
### having
```common-lisp
(having (:>= (:sum :hoge) 88))
;=> #= 88)>
```
### returning
```common-lisp
(returning :id)
;=> #
```
### limit
```common-lisp
(limit 10)
;=> #
(limit 0 10)
;=> #
(yield *)
;=> "LIMIT 0, 10"
; NIL
```
### offset
```common-lisp
(offset 0)
;=> #
(yield *)
;=> "OFFSET 0"
; NIL
```
### inner-join, left-join, right-join, full-join
```common-lisp
(inner-join :person_config :on (:= :person.config_id :person_config.id))
;=> #
(left-join :person_config :on (:= :person.config_id :person_config.id))
;=> #
(left-join :person_config :using :config_id)
;=> #
```
### primary-key
```common-lisp
(primary-key :id)
;=> #
(primary-key '(:id))
;=> #
(primary-key "id_index" '(:id))
;=> #
```
### unique-key
```common-lisp
(unique-key '(:name :country))
;=> #
(unique-key "name_and_country_index" '(:name :country))
;=> #
```
### index-key
```common-lisp
(index-key (:name :country))
;=> #
(index-key "name_and_country_index" '(:name :country))
;=> #
```
### foreign-key
```common-lisp
(foreign-key '(:project_id) :references '(:project :id))
;=> #
(foreign-key '(:user_id) :references '(:user :id) :on-delete :cascade)
;=> #
```
### add-column
```common-lisp
(add-column :updated_at :type 'integer :default 0 :not-null t :after :created_at)
;=> #
```
### modify-column
```common-lisp
(modify-column :updated_at :type 'datetime :not-null t)
;=> #
```
### alter-column
```common-lisp
(alter-column :user :type '(:varchar 64))
;=> #
(alter-column :id :set-default 1)
;=> #
(alter-column :id :drop-default t)
;=> #
(alter-column :profile :not-null t)
;=> #
```
### change-column
```common-lisp
(change-column :updated_at :updated_on)
;=> #
```
### drop-column
```common-lisp
(drop-column :updated_on)
;=> #
```
### add-primary-key
```common-lisp
(add-primary-key :id :name)
;=> #
```
### drop-primary-key
```common-lisp
(drop-primary-key)
;=> #
```
### rename-to
```common-lisp
(rename-to :users)
;=> #
(alter-table :user
(rename-to :users))
;=> #
```
### on-duplicate-key-update
Support MySQL's `INSERT ... ON DUPLICATE KEY UPDATE` syntax.
```common-lisp
(on-duplicate-key-update :age (:+ :age 1))
;=> #
(insert-into :person
(set= :sex "male"
:age 25
:name "Eitaro Fukamachi")
(on-duplicate-key-update :age (:+ :age 1)))
;=> #
```
### on-coflict-do-nothing
Support PostgreSQL's `INSERT ... ON CONFLICT DO NOTHING` syntax.
```common-lisp
(on-conflict-do-nothing)
;=> #
(on-conflict-do-nothing :index_name)
;=> #
(on-conflict-do-nothing '(:column1 :column2 :column3))
;=> #
```
### on-coflict-do-update
Support PostgreSQL's `INSERT ... ON CONFLICT ... DO UPDATE` syntax.
```common-lisp
(on-conflict-do-update :index_name (set= :x 1 :y 2))
;=> #
(on-conflict-do-update '(:column1 :column2 :column3) (set= :x 1 :y 2))
;=> #
(insert-into :person
(set= :sex "male"
:age 25
:name "Eitaro Fukamachi")
(on-conflict-do-update '(:name)
(set= :age (:+ :age 1))
(where (:< :age 99))))
;=> #
```
## SQL Operators
* :not
* :is-null, :not-null
* :asc, :desc
* :distinct
* :=, :!=
* :<, :>, :<= :>=
* :a<, :a>
* :as
* :in, :not-in
* :like
* :and, :or
* :+, :-, :* :/ :%
* :raw
* :is-distinct-from, :is-not-distinct-from (Postgres)
## Set a quote character
`*quote-character*` is the character that a table or column name will be quoted with. The default value is NIL (not quote).
```common-lisp
(yield (select :* (from 'table)))
;=> "SELECT * FROM table"
; NIL
;; for MySQL
(let ((*quote-character* #\`))
(yield (select :* (from 'table))))
;=> "SELECT * FROM `table`"
; NIL
;; for PostgreSQL
(let ((*quote-character* #\"))
(yield (select :* (from 'table))))
;=> "SELECT * FROM "table""
; NIL
```
## Author
* Eitaro Fukamachi (e.arrows@gmail.com)
## Copyright
Copyright (c) 2013-2014 Eitaro Fukamachi (e.arrows@gmail.com)
# License
Licensed under the BSD 3-Clause License.