An open API service indexing awesome lists of open source software.

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.

Awesome Lists containing this project

README

          

# SxQL - An SQL generator.

[![Build Status](https://travis-ci.org/fukamachi/sxql.svg?branch=master)](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.