Squel.js
- lightweight Javascript library for building SQL query strings.
- usable with node.js or in the browser.
- well tested (over 300 vows).
To install for node.js use npm:
npm install squel
Once done you can use require to access the API:
var squel = require("squel");
To use within a webpage include the following within your HTML body section, near the bottom:
<script type="text/javascript" src="/your/path/to/squel.min.js"></script>
Once loaded the squel API will be available in the global object:
alert( typeof window.squel ); // object
Note: Most of the code examples on this page are clickable. Look for ones containing an alert call.
Squel helps you quickly and easily build SQL query strings through an object oriented API.
There are two main benefits to using Squel to build your queries:
Ok, now you're convinced! Before you get stuck in here are a few things to be aware of...
Squel uses method chaining to make things easy. For example, instead of writing:
var s = squel.select();
s.from("student");
alert( s.toString() ); /* SELECT * FROM student */
You can simply write:
alert( squel.select().from("students").toString() ); // SELECT * FROM students
What's even better, the toString() method gets called automatically by the Javascript interpreter
whenever a string representation of an object is needed. So we can actually simplify the previous statement to:
alert( squel.select().from("students") ); /* SELECT * FROM students */
Note: All of Squel's builders provide the toString() method. It is this
method which constructs the final query string.
Squel does not check to see if your final query is semantically correct (i.e. that it makes sense). Your database engine already does a good enough job of that. On the plus side Squel allows you to use proprietary database functions and other complex constructs:
alert(
squel.select()
.from("students")
.field("name")
.field("MIN(test_score)")
.field("MAX(test_score)")
.field("GROUP_CONCAT(DISTINCT test_score ORDER BY test_score DESC SEPARATOR ' ')")
.group("name")
);
/*
SELECT
name,
MIN(test_score),
MAX(test_score),
GROUP_CONCAT(DISTINCT test_score ORDER BY test_score DESC SEPARATOR ' ')
FROM
students
GROUP BY
name
*/
Note: Unless stated otherwise all query builder methods require string arguments. Passing in objects, arrays or functions will result in exceptions being thrown.
To get an instance of the SELECT query builder:
var q = squel.select();
Calling toString() on it now will throw an exception:
try {
alert( squel.select() ); /* remember that toString() is implicitly called here */
} catch (error) {
alert( error ); /* from() needs to be called */
}
Thus, at a minimum the name of a table to fetch data from must be provided:
alert(
squel.select()
.from("students")
);
/* SELECT * FROM students */
You can select data from multiple tables and provide aliases where needed:
alert(
squel.select()
.from("students")
.from("lecturers", "l")
.from("admins")
);
/* SELECT * FROM students, lecturers `l`, admins */
You can specify field names on their own or by the table they belong to:
alert(
squel.select()
.from("students")
.field("id")
.field("students.name")
);
/* SELECT id, students.name FROM students */
Field names can be given aliases in order to customize the column names in the query results :
alert(
squel.select()
.from("students")
.field("id", "Id")
.field("students.name", "Student Name")
);
/* SELECT id AS "Id", students.name AS "Student Name" FROM students */
Database functions can be used in place of field names for more complex results:
alert(
squel.select()
.from("students", "s")
.field("s.id")
.field("s.test_score", "Test score")
.field("DATE_FORMAT(s.date_taken, '%M %Y')", "Taken on")
);
/*
SELECT
s.id,
s.test_score AS "Test score"
DATE_FORMAT(s.date_taken, '%M %Y') AS "Taken on"
FROM
students `s`
*/
If you wish to obtain DISTINCT results you can do so:
alert(
squel.select()
.from("students")
.field("id")
.distinct()
);
/* SELECT DISTINCT id FROM students */
INNER, OUTER, LEFT and RIGHT joins. To do an
INNER join:
alert(
squel.select()
.from("students")
.join("teachers")
);
/* SELECT * FROM students INNER JOIN teachers */
You can specify table aliases:
alert(
squel.select()
.from("students")
.join("teachers", "t")
.outer_join("expelled")
);
/* SELECT * FROM students
INNER JOIN teachers `t`
OUTER JOIN expelled
*/
And you can specify JOIN-ing conditions:
alert(
squel.select()
.field("students.id")
.from("students")
.left_join("teachers", null, "students.id = teachers.student_id")
.right_join("jailed", "j", "j.student_id = students.id")
);
/* SELECT students.id FROM students
LEFT JOIN teachers ON (students.id = teachers.student_id)
RIGHT JOIN jailed `j` ON (j.student_id = students.id)
*/
For an optional parameter such as an alias name, passing null is the same as omitting it.
You can add WHERE clause filtering to your query very easily:
alert(
squel.select()
.field("id")
.from("students")
.where("name = 'Thomas'")
);
/* SELECT id FROM students WHERE (name = 'Thomas') */
Multiple filters are automatically combined using AND:
alert(
squel.select()
.field("id")
.from("students")
.where("name = 'Thomas'")
.where("age > 18")
);
/* SELECT id FROM students WHERE (name = 'Thomas') AND (age > 18) */
Also filter using OR or any other operator you like:
alert(
squel.select()
.field("id")
.from("students")
.where("name = 'Thomas' OR age > 18")
.where("id BETWEEN 200 and 300")
);
/* SELECT id FROM students WHERE (name = 'Thomas' OR age > 18) AND (id BETWEEN 200 and 300) */
You can also pass in Expressions:
alert(
squel.select()
.field("id")
.from("students")
.where(
squel.expr().and("name = 'Thomas'").or("age > 18")
)
);
/* SELECT id FROM students WHERE (name = 'Thomas' OR age > 18) */
alert(
squel.select()
.field("id")
.from("students")
.order("id")
.order("name")
);
/* SELECT id FROM students ORDER BY id ASC, name ASC */
Use the second argument of order() to change the direction of a sort:
alert(
squel.select()
.field("id")
.from("students")
.order("id")
.order("name", false) /* using TRUE instead would be the same as omitting it. */
);
/* SELECT id FROM students ORDER BY id ASC, name DESC */
alert(
squel.select()
.field("id")
.from("students")
.group("id")
);
/* SELECT id FROM students GR0UP BY id */
Grouping on multiple fields is supported:
alert(
squel.select()
.field("id")
.from("students")
.group("id")
.group("students.name")
);
/* SELECT id FROM students GR0UP BY id, students.name */
To LIMIT the number of results:
alert(
squel.select()
.from("students")
.limit(10)
);
/* SELECT * FROM students LIMIT 10 */
To remove the previously set limit:
alert(
squel.select()
.from("students")
.limit(10)
.limit(0)
);
/* SELECT * FROM students */
To specify the OFFSET of the first row to return:
alert(
squel.select()
.from("students")
.offset(102)
);
/* SELECT * FROM students OFFSET 102 */
Same as for limit(), you can remove a previously set offset:
alert(
squel.select()
.from("students")
.offset(1)
.offset(0)
);
/* SELECT * FROM students */
To get an instance of the UPDATE query builder:
var q = squel.update();
You need to supply at least one table name and one field to update:
alert(
squel.update()
.table("students")
.set("name", "Thomas")
);
/* UPDATE students SET name = "Thomas" */
Multiple table names can be supplied along with aliases:
alert(
squel.update()
.table("students")
.table("teachers", "t")
.set("t.name", "Fred")
);
/* UPDATE students, teachers `t` SET t.name = "Fred" */
Not all field values within a query need to be surrounded by quotes. Squel figures out how to represent each field value based on its runtime type:
alert(
squel.update()
.table("students")
.set("name", "Fred")
.set("age", 29)
.set("score", 1.2)
.set("graduate", false)
);
/* UPDATE students SET name = "Fred", age = 29, score = 1.2, graduate = FALSE */
You can even use NULL values:
alert(
squel.update()
.table("students")
.set("name", "Fred")
.set("age", 29)
.set("nickname", null)
);
/* UPDATE students SET name = "Fred", age = 29, nickname = NULL */
You can use the usingValuePlaceholders option to stop Squel from automatically placing string
field values within quotes. This is useful if, for example, you're using parameterized queries:
alert(
squel.update({ usingValuePlaceholders: true })
.table("students")
.set("name", "?")
.set("age", 29)
.set("nickname", null)
);
/* UPDATE students SET name = ?, age = 29, nickname = NULL */
The where(), order() and limit() methods are supported the same
way they are by the SELECT builder:
alert(
squel.update()
.table("students")
.set("name", "Fred")
.set("age", 29)
.where("id > 5")
.where("id < 102")
.order("id", false)
.limit(5)
);
/* UPDATE students SET name = "Fred", age = 29 WHERE (id > 5) AND (id < 102) ORDER BY id DESC LIMIT 5 */
To get an instance of the DELETE query builder:
var q = squel.delete();
You need to supply at least the table name:
alert(
squel.delete()
.from("students")
);
/* DELETE FROM students */
The where(), order() and limit() methods are supported the same way
they are by the SELECT builder:
alert(
squel.delete()
.from("students")
.where("id > 5")
.where("id < 102")
.order("id", false)
.limit(5)
);
/* DELETE FROM students WHERE (id > 5) AND (id < 102) ORDER BY id DESC LIMIT 5 */
To get an instance of the INSERT query builder:
var q = squel.insert();
At least the table name and one field must be supplied:
alert(
squel.insert()
.into("students")
.set("name", "Thomas")
);
/* INSERT INTO students (name) VALUES ("Thomas") */
Squel out how to treat each field value based on its runtime type, same as it does for UPDATE queries:
alert(
squel.insert()
.into("students")
.set("name", "Thomas")
.set("age", 29)
.set("score", 90.2)
.set("graduate", true)
.set("nickname", null)
);
/* INSERT INTO students (name, age, score, graduate, nickname) VALUES ("Thomas", 29, 90.2, TRUE, NULL) */
And same as for UPDATE queries, you can use the usingValuePlaceholders option to
stop Squel from automatically placing string field values within quotes:
alert(
squel.insert({ usingValuePlaceholders: true })
.into("students")
.set("name", "?")
.set("age", 29)
.set("score", 90.2)
.set("graduate", true)
.set("nickname", null)
);
/* INSERT INTO students (name, age, score, graduate, nickname) VALUES (?, 29, 90.2, TRUE, NULL) */
Squel lets you use use complex expressions strings in WHERE and ON clauses. For
example:
alert(
squel.select()
.from("students")
.where("(id < 500 AND (id > 100 OR name <> 'Thomas') AND "
+ "(age BETWEEN 20 AND 25 OR (name <> 'Fred'))) OR (nickname = 'Hardy')")
);
/* SELECT * FROM students WHERE
((id < 500 AND (id > 100 OR name <> 'Thomas') AND (age BETWEEN 20 AND 25 OR (name <> 'Fred')))
OR (nickname = 'Hardy')) */
But having to change an expression string like that later on will be error-prone. It would be nice if you could build it the same way you build queries. Luckily Squel provides an expression builder just for this purpose. To get an instance of the builder:
var q = squel.expr();
To build the above expression string these are the calls you would make:
alert(
squel.expr()
.and("id < 500")
.and_begin()
.or("id > 100")
.or("name <> 'Thomas'")
.end()
.and_begin()
.or("age BETWEEN 20 AND 25")
.or("name <> 'Fred'")
.end()
.or("nickname = 'Hardy'")
);
/* id < 500 AND (id > 100 OR name <> 'Thomas') AND (age BETWEEN 20 AND 25 OR name <> 'Fred')
OR nickname = 'Hardy'
*/
Straight away the benefit of using the expression builder can be seen as it has simplified the
expression (AND has precendence over OR). Not to mention that it's easier to
figure out the meaning of the expression looking at this code than from the big string we were
using earlier.
As a convenience expression builder instances can be used in calls to where() and
join() when using the query builders:
alert(
squel.select()
.field("s.id")
.from("students", "s")
.where(
squel.expr()
.and("s.name <> 'Fred'")
.or_begin()
.or("s.id = 5")
.or("s.id = 6")
.end()
)
.join("teachers", "t",
squel.expr()
.and("s.id = t.sid")
.and("t.name = 'Frances'")
)
);
/*
SELECT s.id FROM students `s`
INNER JOIN teachers `t` ON (s.id = t.sid AND t.name = 'Frances')
WHERE (s.name <> 'Fred' AND (s.id = 5 OR s.id = 6))
*/
Tests are written as vows and can be found in the test/ folder when you checkout the
source code.
To run them do the following:
$ npm install
$ node_modules/.bin/cake tests
If the tests pass you should see something like this:
✓ OK » 320 honored (0.236s)
The tests get automatically run by the Travis CI
build system every time changes are made to Squel.
The current build status is: