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 🙏

© 2024 – Pkg Stats / Ryan Hefner

fluent-sql

v3.0.5

Published

Fluent SQL lib

Downloads

21

Readme

README

This library basically takes your fluent SQL and generates SQL strings and replacement

What is this repository for?

  • Quick summary I needed a javascript version of the same library I wrote for java (mainly because I just liked the flow)
  • Examples

Create your table

const users = new SqlTable({
  TableName: 'users',
  columns: [{ ColumnName: 'id' }, { ColumnName: 'username' }, { ColumnName: 'password' }],
});
const bank = new SqlTable({
  TableName: 'bank_account',
  columns: [{ ColumnName: 'id' }, { ColumnName: 'user_id' }, { ColumnName: 'account_no' }, { ColumnName: 'balance' }],
});

NOTE: column names will be changed to camelCase from snake_case

Create your query. SqlQuery takes an options object.

  • SqlQuery object to copy options from OR

  • an object of options

    • sqlStartChar - character used to escape names
      • default is '['
    • sqlEndChar - character used to end escaped names
      • default is ']'
    • escapeLevel - array of zero or more ('table-alias', 'column-alias')
      • default is ['table-alias', 'column-alias']
    • namedValues - boolean, if false will use ? for the values and just return an array of values
      • default true
    • namedValueMarker - character, will use this with named values in the generated SQL (example: where foo = (:value0))
      • default is ':'
    • markerType - 'number' or 'name' if number will generate :1, ..., :n number is 1 based
      • default is 'name'
    • dialect - 'pg' = postgreSQL, 'MS' = SQLServer subtle changes to the generated SQL (TOP vs. LIMIT for example)
      • default is 'MS'
    • recordSetPaging - true/false
      • default is false
  • Non-record set paging

    • MS dialect
select * from some-table where x > 1
offset 0 rows
fetch next 50 rows only
  • Non-record set paging
    • pg dialect
select * from some-table where x > 1
limit 50 offset 0
  • Record Set Paging
SELECT * FROM (
	SELECT *, row_number() OVER (ORDER BY name ASC) as Paging_RowNumber FROM (
    select * from some-table where x > 1
	) base_query
) as detail_query WHERE Paging_RowNumber BETWEEN 0 AND 50
import { setPostgres, setSqlServer } from 'fluent-sql';

setPostgres(); // from here forward sqlQuery will use postgres options

the following are the options set by setPostgres/setSqlServer

export const postgresOptions = {
  sqlStartChar: '"',
  sqlEndChar: '"',
  namedValues: true,
  namedValueMarker: '$',
  markerType: 'number',
  dialect: 'pg',
  recordSetPaging: false,
};
export const sqlServerOptions = {
  sqlStartChar: '[',
  sqlEndChar: ']',
  escapeLevel: ['table-alias', 'column-alias'],
  namedValues: true,
  namedValueMarker: ':',
  markerType: 'name',
  dialect: 'MS',
  recordSetPaging: false,
};
const query = new SqlQuery()
  .select(users.id, users.username, users.password)
  .from(users)
  .where(users.username.eq('jsmith'));

Get your SQL

const sql = query.genSql(decryptFunction, maskingFunction);

Sql looks like the following (MS Dialect)

{
  fetchSql:
   'SELECT\n[users].id as [id],\n[users].username as [username],\n[users].password as [password]\nFROM\nusers as [users]\nWHERE [users].username = (:username0)',
  countSql: undefined,
  hasEncrypted: false,
  values: {
    username0: 'jsmith'
  }
}

Sql looks like the following (Postgres)

{
  fetchSql:
   'SELECT\n"users".id as "id",\n"users".username as "username",\n"users".password as "password"\nFROM\nusers as "users"\nWHERE "users".username = ($1)',
  countSql: undefined,
  hasEncrypted: false,
  values: [ 'jsmith' ]
}

Decrypt & Masking functions are just a function that takes 2 parameters, SqlColumn and boolean on weather or not to use a fully qualified column name (ie. table.col), you can do anything in these and return null or a SQL literal to insert for that column in the generated SQL. Both functions can be NULL

The sql returned is an object

  • fetchSql - the actual sql statement to fetch the data
  • countSql - a count(*) with the same where statement
  • hasEncrypted - boolean to say if the encrypted function ever returned something other than null
  • values - object of the values you used in the query

Aggregate example

const query = new SqlQuery().select(bank.balance.sum().by(bank.userId)).from(bank);

generates:

SELECT SUM(bank_account.balance) as balance_sum
FROM bank_account as bank_account
GROUP BY bank_account.user_id

Limits & paging

  • top, limit, take, & pageSize = all set the record count returned the last called wins
  • offet & skip = how many records to skip
  • page = cannot be used with offset or skip MUST have a top, limit, take, or pageSize
const query = new SqlQuery()
  .select(users.id)
  .page(5)
  .pageSize(10);

Update/Insert

const insert = bank.insert({ id: 1, userId: 1, accountNo: 1, balance: 1000.0 });
const update = bank.update({ id: 1, balance: 1000.0 });
  • insert/update structure
    • sql - sql for INSERT/UPDATE
    • values - object of the values used in the sql

Look through the tests for more examples, the tests should have every possible option exercised

How do I get set up?

npm install fluent-sql

Generate SqlTable classes from database (supports Sqlite and postgres)

  • npm i -D simple-db-migrate (I used my command line parsing from this module)
  • npm i -D sqlite3 or npm i -D pg if you are not using one of these already
  • exec fluent-sql-gen
  • command line options
    • --verbose, -v toggle on
    • --dialect, -d one of [pg, sqlite]
    • --database, -db string
    • --user, -u string
    • --password, -p string
    • --host, -h string
    • --port number
  • defaults are
    • --dialect=sqlite -db db.sqlite

Other npm packages

https://www.npmjs.com/package/simple-db-migrate

  • dead simple database migrations

change history

  • did a terrible job up till now on this

  • 3.0.0

    • added TypeScript, entire source is now ts
  • 2.6.0

    • added 'fluent-sql-gen' to create SqlTable classes from database
  • 2.5.0

    • Completely changed the generated SQL for paging.
    • Added recordSetPaging option to get old behavior

TODO:

  • add outer join
  • add generator for tables/columns