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

sqljson

v0.0.1

Published

Convert results of sql to json. Converts json into a sql statement.

Downloads

6

Readme

SqlJson

SqlJson is a standard data format used to convert SQL to JSON and JSON to SQL.

SqlJson is especially useful for mapping hierarchial JSON to SQL and visa versa.

Warning: This is a new project and we're working on the standard. As such, it may change.

Introduction

We hope this standard will be implemented in different languages (Java, Javascript, C#, Objective-C, etc.). We're starting with Javascript due to it's native support of JSON.

What SqlJson Isn't!

  • SqlJson is not an ORM (Object Resource Manager)[^1]. It is a data format standard.
  • SqlJson, at this time, does not support transactions.
  • SqlJson does not understand models[^2].
  • SqlJson does not validate SQL. It is a data format standard.
  • SqlJson, currently, does not know what flavor of SQL is being used.

Documentation

SqlJson: Introduction

Example RESTful Service

$ npm install // don't forget this
$ cd examples/crm
$ node server.js
// browse to http://localhost:3000/individuals

SqlJson: Basic Format

SqlJson has the following basic format:

  • sqlJson - Placed at the root of your JSON.
  • sql - Contains SQL statement(s) used to generate and/or save JSON.
  • dataPath - For database reads, the location of a property in the JSON where SQL results are placed. For database writes, the location of a property in the JSON containting data to store in the database.
    • TODO: Support JSONPath syntax
  • sourceProperty - Name of property in JSON to place the SQL results.
  • type - The primitive data type of the dataPath. See Type.
{
  sqlJson: {
    sql: `SELECT * FROM account;`,
    dataPath: 'accounts',
    type: 'array'
  }
}

becomes:

{
  accounts: [<account data>]
}

Type

The results of a SQL call can be one of the following types:

  • array
  • object
  • string
  • number

The type can be determined based on the type property or based on the existing type of the destination property.

An Array

{
  sqlJson: {
    sql: `SELECT * FROM account;`,
    dataPath: 'accounts'
  },
  accounts: []
}

Because the accounts property is initialized to an array, SqlJson will populate the array with the results of the Sql call: even if only one item is returned. SqlJson will leave the array empty if no items are returned.

An Object

{
  sqlJson: {
    sql: `SELECT * FROM account WHERE account_id = 1;`,
    dataPath: 'accounts'
  },
}

Because the accounts property is initialized to an object, SqlJson will populate the object with the results of the Sql call. An exception is thrown if more than one row is returned from the Sql call. If no rows are returned, accounts would be set to undefined[^3].

A Primitive Type

{
  accountNameSql: `
    SELECT account_name AS accountName
    FROM account
    WHERE account_id = 1;`,
  accountName: ''
}

Because the account property is initialized to an empty string, SqlJson will populate the object with the results of the accountName field of the Sql call. An exception is thrown if more than one row is returned from the Sql call. If no rows are returned, account would be set to undefined[^3].

No Type Provided

{
  accountSql: `SELECT * FROM account;`
}

or

{
  accountSql: `SELECT * FROM account;`,
  account: undefined
}

Because no property is provided or the property is undefined, SqlJson will do the following:

  • One Result: SqlJson will create an object, populate the object, and place that object in the property. A single result will never result in a primitive data type.
  • Multiple Results: SqlJson will create an array, fill the array with the results, and place the array in the property.

Features

SQL snake-case to Javascript camelCase

By default, SqlJson will convert SQL snake-case naming convention to Javascript camelCase.

The following two selects return the same JSON object:

SELECT account_id AS accountId,
      first_name AS firstName,
      family_name AS familyName,
FROM account;

and

SELECT account_id,
      first_name,
      family_name,
FROM account;

result in JSON with properties of accountId, firstName and familyName.

SQL to JSON - SQL SELECT

To read from a SQL database and convert results to JSON use the following SqlJson format:

var selectExample = {
  sqlJson: {
    sql: `SELECT account_id AS accountId,
                 first_name AS firstName,
                 family_name AS familyName,
          FROM account;`,
    dataPath: 'accounts',
    type: 'array'
  }
}

The Query result is placed at the root of the JSON in a property named accounts.

Let's assume there are two records in the account table.

var repoSqlite3 = sqljsonlib.repoSqlite3({
  afterOpen: () => {
    var sqljson = sqljsonlib.sqljson(repoSqlite3);
        sqljson.run(selectExample, (err, res) => {
          console.log(res);
        });
  });
  reposqllite3.run;

will log to the console:

{
  accounts: [{
    accountId: '961fe224-8943-47fb-b08a-92123d9d7211',
    firstName: 'Candy',
    familyName: 'Lacy'
  }, {
    accountId: 'cb89b50c-65e0-4ed5-a8ed-fb240b3b2830',
    firstName: 'Arnold',
    familyName: 'Lane'
  }]
}

JSON to SQL - SQL INSERT

To convert and persist JSON to SQL use the following SqlJson format:

var insertExample = {
  sqlJson: {
    sql: `INSERT INTO account(account_id, first_name, family_name)
          VALUES(:accountId, :firstName, :familyName);`,
   dataPath: 'accounts'
  },
  accounts : [{
    accountId: '961fe224-8943-47fb-b08a-92123d9d7211',
    firstName: 'Candy',
    lastName: 'Lacy'
  }, {
    accountId: 'cb89b50c-65e0-4ed5-a8ed-fb240b3b2830',
    firstName: 'Arnold',
    lastName: 'Lane'
  }]
}
  • The :[JSONPath] is used to locate values within the json to generate the SQL.
    • TODO: Implement JSONPath support.

The following generates and runs SQL against the repository:

var repoSqlite3 = sqljsonlib.repoSqlite3({
  afterOpen: () => {
    var sqljson = sqljsonlib.sqljson(repoSqlite3);
        sqljson.run(insertExample, (err, res) => {
          console.log(res);
        });
  });
  reposqllite3.run;

Under the hood, the followig SQL is generated:

INSERT INTO users(
  user_id, email            , display_name , password ) VALUES
( 1      , "[email protected]" , "First User" , "1234"   ),
( 2      , "[email protected]", "Second User", "5678"   );

Variables In SQL

SqlJson supports variables within the SQL that are replaced by SqlJson before executing the SQL.

var selectInExample = {
  sqlJson: {
    sql: `SELECT account_id AS accountId,
                 first_name AS firstName,
                 family_name AS familyName,
          FROM account
          WHERE account_id IN (:userIds);`,
  },
  userIds: ['961fe224-8943-47fb-b08a-92123d9d7211',
              'cb89b50c-65e0-4ed5-a8ed-fb240b3b2830']
};

Under the hood, the following SQL statement is generated.

SELECT account_id AS accountId,
       first_name AS firstName,
       family_name AS familyName,
FROM account
WHERE account_id IN
  ('961fe224-8943-47fb-b08a-92123d9d7211',
  'cb89b50c-65e0-4ed5-a8ed-fb240b3b2830');

Multiple Selects At Same Object Level

SqlJson supports multiple SQL statements within an object. Note that sqlJson is now an array:

var multipleStatements = {
  sqlJson: [{
    sql: `SELECT account_id AS accountId,
           first_name AS firstName,
           family_name AS familyName,
    FROM account;`,
    dataPath: 'accounts',
    type: 'array'
  }, {
    sql: `SELECT invoice_id AS invoiceId,
           account_id AS accountId,
           description
    FROM invoice;`,
    dataPath: 'invoices',
    type: 'array'
  }]
}

becomes:

{
  accounts: [<account data>],
  invoices: [<invoice data>]
}

Hierarchical Selects

SqlJson supports converting nested SQL hierarchies to JSON.

{
  sqlJson: {
    sql: `SELECT account_id AS accountId,
                 first_name AS firstName,
                 family_name AS familyName
          FROM account;`,
    dataPath: 'accounts',
    type: 'array',
    sqlJson: {
      sql: `SELECT invoice_id AS invoiceId,
                   account_id AS accountId,
                   description
            FROM invoice`,
      dataPath: 'invoices',
      type: 'array',
      relationship: {
        parent: 'accountId',
        child: 'accountId',
        type: 'array',
        includeForeignKey: false
      }
    }
  }
}

The relationship is defined in the child using the relationship property and following structure:

{
  parent: 'accountId',
  child: 'accountId',
  type: 'array'
}
  • Parent === Child - A comparison is done using the parent property name and child property name.
  • type - Expected type of the Parent property children are placed into. By default, this is an array.
  • includeForeignKey - When true, the foreign key of the child is included in the final JSON. When false, the key of the child is not included in the final JSON.

Example output:

{
  accounts: [{
    accountId: '961fe224-8943-47fb-b08a-92123d9d7211',
    firstName: 'Candy',
    familyName: 'Lacy',
    invoices: [{
      invoiceId: 'f91dc9ca-bb9d-4952-85ae-b73ac876de7d',
      description: 'First Invoice'
    }, {
      invoiceId: 'ad5e6b4d-623b-46f1-a4ae-ba41d40b5dab',
      description: 'Second Invoice'
    }]
  }, {
    accountId: 'cb89b50c-65e0-4ed5-a8ed-fb240b3b2830',
    firstName: 'Arnold',
    familyName: 'Lane',
    invoices: [{
      invoiceId: '2d42e427-8f40-47f7-b8d1-dfc1e9ee3237',
      description: 'Third Invoice'
    }]
  }]
}

Notice invoices are now properties of accounts. Since includeForeignKey is false, the accountId foreign key is not part of the invoices JSON.

Future Features

  • Use JSONPath, instead of just a property name, to get data from the data property.
  • Provide information on sql format standard (Oracle, MySql, sqlite, etc.). May not be required/beyond scope.
  • Some kind of security so people can't do things like accidentally drop a database. Could be beyond scope.
  • Invalid sql statments are not valided by us. We will just take the results from back end server and display them if the sql is invalid.
  • sqljson should return how many rows update
  • Perhaps provide non-array for sqljson.data property in the future.
  • Use table schema to figure out data type in SQL database. For now use values in json. Or, maybe, in future, assure json datatype matches sql.
  • CONSIDER: Provide the final SQL statement used to SELECT data and/or provide an option to return it as part of the result?

Features Considered and Not Implemented

Setup

Install:

$ npm install

Continuous test:

$ gulp

Test:

$ gulp webtests

Test Server

Read documentation in gulpfile.js to see how to setup automated web testing.

$ gulp webserver

Research

Node Packages

https://www.npmjs.com/package/jsonsql https://www.npmjs.com/package/json-sql https://www.npmjs.com/package/json-to-sql - Define a sql statement in Json. https://www.npmjs.com/package/sql-insert-to-json https://www.npmjs.com/package/sql-json-transformer

[^1]: SqlJson would be a good data format to build an ORM on top of. [^2]: You can always add meta-data to your json which you can later use to map the results to models. [^3]: Javascript Null is not used within this framework: something recommended by Douglas Crockford.