npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

norm-sql

v1.3.0

Published

A SQL builder that doesn't force its opinions on you. Paste SQL together, but with flexibility.

Downloads

44

Readme

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.