1.3.0 • Published 10 years ago

norm-sql v1.3.0

Weekly downloads
7
License
ISC
Repository
github
Last release
10 years ago

Build Status

norm

A SQL builder that doesn't force its opinions on you. Just pastes SQL together in a constructive manner.

How will this make your life better? If you've never used a SQL builder:

  • SQL objects are composable like functions
  • SQL looks much more natural inside of your code
  • Binds tracking is handled for you
  • Arrays of values are gracefully handled

What's different about norm-sql?

  • No setting up copies of schemas in javascript, just start writing SQL
  • Expressive logical operators that are simple to use
  • Easy to adapt to most SQL engines
  • Small module size - no mysteries!
  • No production dependencies
  • Supports MySQL/MariaDB/Oracle binds (?) and Postgres prepared statements ($1)

Check out the examples below to get a handle on what this looks like in practice.

Installation

npm install norm-sql

Examples

Simple Select Example

Supported Clauses: select, distinct, from, where, groupby, having, orderby, limit

var norm = require('norm-sql');

var query = norm()
	.select("users.id", "users.username")
	.from("users")
	.where(
		[ "users.powerlevel >= ?", 9000 ],
		"users.created >= NOW() - INTERVAL 1000 YEAR"
	)
	.limit(1);

console.log(query.sql());
console.log(query.binds());

Output:
>> 'select users.id, users.username from users where users.powerlevel >= ? limit 1'
>> [ 9000 ]

Subquery Example

var norm = require('norm-sql');

var national_query = norm()
	.select("sum(nations.gdp)")
	.from("nations")
	.where(
		"nations.planetid = planets.id",
		"nations.deleted is null"
	);

var planetary_query = norm()
		.select(
			"planets.id", 
			"planets.name",
			[ "(?) GPP", national_query ]
		)
		.from("planets")
		.where(
			"GPP > 0",
			[ "planets.au < ?", 50 ]
		);

console.log(planetary_query.sql());
console.log(planetary_query.binds());

Output:
>> 'select planets.id, planets.name, (select sum(nations.gdp) from nations where nations.planetid = planets.id and nations.deleted is null) GPP from planets where GPP > 0 and planets.au < ?'
>> [ 50 ]

Constructing Similar Queries

Start with the planetary_query from the last example:

var real_planetary_query = planetary_query.clone().where("planets.deleted is null");

console.log(planetary_query.sql());

Output:
>> 'select planets.id, planets.name, (select sum(nations.gdp) from nations where nations.planetid = planets.id and nations.deleted is null) GPP from planets where GPP > 0 and planets.amu < ? and planets.deleted is null'

Sorry Pluto....

Array Binds

Here's a feature that's bizzarely missing in a variety of SQL programming contexts: Array Binds.

var norm = require('norm-sql');

var query = norm()
	.select(
		"meme.id"
	)
	.from(
		"meme"
	)
	.where(
		["meme.name in (?)", [ 'doge', 'nyan', 'ggg' ]]
	);

console.log(query.sql());
console.log(query.binds());

Output:
>> 'select meme.id from meme where meme.name in (?,?,?)'
>> [ 'doge', 'nyan', 'ggg' ]

Synthesizing Logical Expressions

Supported Operators: and, or, nand, nor, xor

By default, clauses like where and having use the and conjunction as it is the most common filter. However, sometimes you want a more complex query.

var norm = require('norm-sql');

var query = norm().select(
		"breakfasts.id",
		"breakfasts.date",
		"breakfasts.type"
	)
	.from("breakfasts")
	.where(
		"breakfasts.date > NOW() - INTERVAL 1 YEAR",
		norm.or(
			[ "breakfasts.type in (?, ?)", 'brunch', 'standard'],
			[ "breakfasts.friend_count > ?", 20 ]
		)
	);

console.log(query.sql());
console.log(query.binds());

Output:
>> 'select breakfasts.id, breakfasts.date, breakfasts.type from breakfasts where breakfasts.date > NOW() - INTERVAL 1 YEAR and (breakfasts.type in (?, ?) or breakfasts.friend_count > ?)'
>> [ 'brunch', 'standard', 20 ]

Note: For more than two inputs, xor is defined as one and only one as opposed to nested binary xors as this is probably more useful.

Update

Supported Clauses: update, set, where, orderby, limit

var norm = require('norm-sql');

var query = norm()
	.update("superheros")
	.set(["superheros.real_first_name = ?", 'bruce'])
	.where(["superheros.id = ?", 1])
	.limit(1);

console.log(query.sql());

Output:
>> 'update superheros set superheros.real_first_name = ? where superheros.id = ?'

Insert

Supported Clauses: insert, values, select

var norm = require('norm-sql');

var values_query_array = norm()
	.insert("superweapons (name)")
	.values(['Death Star'], ['World Devastators']);

console.log(values_query_array.sql())
console.log(values_query_array.binds())

>> 'insert into superweapons (name) values (?),(?)'
>> [ 'Death Star', 'World Devastators' ]

var values_query_hashes = norm()
	.insert("superweapons")
	.values(
		{ name: "Death Star", date: "A Long Time Ago" }, 
		{ name: "World Devastators", date: "A Very Slightly Less Long Time Ago" },
		{ 
			name: "Sun Crusher", 
			date: { 
				raw: true, 
				value: "NOW() - INTERVAL 401241 YEAR",
			}, 
		}
	);

console.log(values_query_array.sql())
console.log(values_query_array.binds())

>> 'insert into superweapons (name, date) values (?,?),(?,?),(?,NOW() - INTERVAL 401241 YEAR)'
>> [ 'Death Star', 'A Long Time Ago', 'World Devastators', 'A Very Slightly Less Long Time Ago', 'Sun Crusher' ]

var select_query = norm()
	.insert("superweapons (name)")
	.select("catastrophes.cause")
	.distinct()
	.from("catastrophes")
	.where("catastrophes.destruction_level > 9000");

console.log(values_query_array.sql())
console.log(values_query_array.binds())

>> 'insert into superweapons (name) select distinct catastrophes.cause from catastophes where catastrophes.destruction_level > 9000'
>> []

Delete

Supported Clauses: delete, using, where, orderby, limit

var norm = require('norm-sql');

var dml = norm()
	.delete("particles")
	.where(
		["particles.membership = ?", 'atom'],
		["particles.class in (?)", ['electron', 'neutron']]
	);

console.log(dml.sql());
console.log(dml.binds());

Output:
>> 'delete from particles where particles.membership = ? and particles.class in (?,?)'
>> [ 'atom', 'electron', 'neutron' ]

Boom.

Switch DB Engines

var norm = require('norm-sql');

norm.engine('postgres'); // default is mysql

var sql = norm()
	.select("game, finished")
	.from("matches")
	.where(
		[ "game in (?, ?)", 'chess', 'thermonuclear_war' ],
		[ "finished = date '?'", '1983-01-01' ]
	);

console.log(dml.sql());
console.log(dml.binds());

Output:
> "select game, finished from matches where game in ($1, $2) and finished = date '$3'"
> [ 'chess', 'themonuclear_war', '1983-01-01' ]

Lesser boom.

1.3.0

10 years ago

1.2.1

10 years ago

1.2.0

10 years ago

1.1.2

10 years ago

1.1.1

10 years ago

1.1.0

10 years ago

1.0.1

10 years ago

1.0.0

10 years ago