Like Lego For Databases
npm install @nano-sql/core
Universal database layer for the client, server & mobile devices. It's like Lego for databases.
Documentation | API Docs | Bugs | Chat
One of the big items that lead me to build nanoSQL was how NoSQL stores are becoming so popular and performant yet none of them have SQL semantics when you need them. It’s like you have to choose between good performance (noSQL/Document Store) or having stable data modeling with advanced query capability (SQL Style). It seems to me that you can have both, you just have to be aware of the tradeoffs. The big idea here is to build a SQL style parser on top of noSQL datastores. This buys you the strong data models (which is critical in my opinion) of SQL style systems and noSQL level performance if you play inside a small set of rules. You can jump outside those rules whenever you like at the cost of speed…and that’s the point. YOU the developer get to make the choice when and how that happens.
| | nanoSQL | TaffyDB| NeDB | LoveField | PouchDB | alaSQL | RxDB | SQL.js | Lunr |
|-----------------|---------|--------|------|-----------|---------|--------|--------|--------|--------|
| Events | ✓ | ✓ | ✕ | ✓ | ✓ | ✕ | ✓ | ✕ | ✕ |
| Typescript | ✓ | ✕ | ✓ | ✓ | ✓ | ✕ | ✓ | ✓ | ✓ |
| Graph Queries | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ |
| Join Queries | ✓ | ✓ | ✓ | ✓ | ✕ | ✓ | ✕ | ✓ | ✕ |
| IndexedDB | ✓ | ✕ | ✕ | ✓ | ✓ | ✓ | ✓ | ✕ | ✕ |
| NodeJS | ✓ | ✓ | ✓ | ✕ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Foreign Keys | ✓ | ✕ | ✕ | ✓ | ✕ | ✓ | ✕ | ✓ | ✕ |
| Query Functions | ✓ | ✕ | ✕ | ✕ | ✕ | ✓ | ✕ | ✓ | ✕ |
| Custom Backends | ✓ | ✕ | ✕ | ✕ | ✓ | ✕ | ✓ | ✕ | ✕ |
| Fuzzy Search * | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✓ |
| Size (kb) | 30 | 5 | 27 | 40 | 46 | 88 | 164 | 500 | 8 |
\* Requires additional plugin not included in the bundle size shown in the table.
NanoSQL can save data to many different places, depending on the browser or environment it's being ran in.
1. Included In The Box
- Memory (Browser/NodeJS/Electron)
- Snap DB (NodeJS/Electron)
- Indexed DB (Browser)
- WebSQL (Browser)
- Local Storage (Browser)
2. RocksDB (NodeJS/Electron)
3. LevelDB (NodeJS/Electron)
4. SQLite (NodeJS/Electron)
5. SQLite (Cordova)
6. SQLite (NativeScript)
7. React Native
8. Redis
9. MySQL
10. Amazon Dynamo DB
11. MongoDB
12. ScyllaDB
``sh`
npm i @nano-sql/core --save
Using in Typescript/Babel project:
`js`
import { nSQL } from "@nano-sql/core";
Using in Node:
`js`
const nSQL = require("@nano-sql/core").nSQL;
To use directly in the browser, drop one of the tags below into your
.`html
`Important
If you are migrating from nanoSQL 1.X to 2.X, please read the migration guide.
Query Examples
`ts
// Persistent Database
nSQL().createDatabase({
id: "test",
mode: "PERM",
tables: [
{
name: "users",
model: {
"id:uuid": {pk: true},
"name:string": {},
"age:int": {},
"meta:obj": {
model: {
"color:string": {}
}
},
"tags:string[]": {default: []}
}
indexes: {
"tags:string[]": {},
"meta.color:string": {},
"age:int": {}
}
}
],
}).then(() => {
return nSQL("users").query("upsert", {name: "Jeb", age: 20, meta: {color: "blue"}, tags: ["some", "tags", "here"]}).exec();
}).then(() => {
return nSQL("users").query("select").exec();
}).then((rows) => {
console.log(rows);
/*
[
{
"id": "64c611b8-0b1e-42f6-af52-5b8289834bba",
"name": "Billy",
"age": 21,
"meta": {
"color": "blue"
},
"tags": [
"some",
"tags",
"here"
]
}
]
*/
});// Graph Queries
nSQL().query("select", ["author[0].name AS author", "body", "comments[0].totalComments AS commentsTotal", "id", "title"]).from({
table: () => fetch("https://jsonplaceholder.typicode.com/posts").then(d => d.json()).then(j => ({rows: j, cache: true})),
as: "posts"
}).graph([
{
key: "author",
with: {
table: () => fetch("https://jsonplaceholder.typicode.com/users").then(d => d.json()).then(j => ({rows: j, cache: true})),
as: "author"
},
on: ["author.id", "=", "posts.userId"]
},
{
key: "comments",
select: ["COUNT(*) as totalComments"],
with: {
table: () => fetch("https://jsonplaceholder.typicode.com/comments").then(d => d.json()).then(j => ({rows: j, cache: true})),
as: "comments"
},
on: ["comments.postId", "=", "posts.id"]
}
]).exec().then((rows) => {
console.log(rows);
/*
"author": "Leanne Graham",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto",
"commentsTotal": 5,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit"
},
{
"author": "Leanne Graham",
"body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla",
"commentsTotal": 5,
"id": 2,
"title": "qui est esse"
}
...
*/
});
// Join Queries
nSQL().query("select", ["posts.id AS id", "posts.title AS title", "comments.name AS comment", "users.name AS name"]).from({
table: () => fetch("https://jsonplaceholder.typicode.com/posts").then(d => d.json()).then(j => ({rows: j, cache: true})),
as: "posts"
}).where(["userId", "=", 3]).join([
{
type: "inner",
with: {
table: () => fetch("https://jsonplaceholder.typicode.com/comments").then(d => d.json()).then(j => ({rows: j, cache: true})),
as: "comments"
},
on: ["posts.id", "=", "comments.postId"]
},
{
type: "inner",
with: {
table: () => fetch("https://jsonplaceholder.typicode.com/users").then(d => d.json()).then(j => ({rows: j, cache: true})),
as: "users"
},
on: ["users.id", "=", "posts.userId"]
}
])
.exec().then((rows) => {
console.log(rows);
/*
[
{
"id": 21,
"title": "asperiores ea ipsam voluptatibus modi minima quia sint",
"comment": "perspiciatis magnam ut eum autem similique explicabo expedita",
"name": "Clementine Bauch"
},
{
"id": 21,
"title": "asperiores ea ipsam voluptatibus modi minima quia sint",
"comment": "officia ullam ut neque earum ipsa et fuga",
"name": "Clementine Bauch"
},
.....
]
*/
})
`CLI
The nanoSQL command line interface allows you to compile data models into typescript interface files.
Usage is as follows:
`sh
nsql --outDir www --files file1.ts file2.ts... --watch
`If you don't pass
--watch the CLI will compile the files into the given directory, then exit. You can also optionally pass --watchPolling with an interval to enable polling on the watch system.It's important to note the files must be formatted specifically for the CLI to read them correctly.
Each file should have an export named
tables that is an array of InanoSQLTableConfig types. The file below is a working example:`ts
import { InanoSQLTableConfig } from "@nano-sql/core/lib/interfaces";export const tables: InanoSQLTableConfig[] = [
{
name: "users",
model: {
"id:uuid": {pk: true},
"age:float": {notNull: true},
"name:string[]": {default: []},
"properties:meta[]": {},
"address:obj": {
model: {
"street:string":{},
"city:string":{},
"zip:string":{},
"state:string":{}
}
},
"*:any": {}
}
}
];
export const types = {
meta: {
"key:string": {notNull: true},
"value:any": {notNull: true}
}
}
// using the above object in nSQL
import { nSQL } from "@nano-sql/core";
nSQL().createDatabase({
id: "my_db",
tables: tables,
types: types
}).then..
`Assuming the above file is in the root directory of our project named index.ts, we could compile it to a typescript interface file with this command:
`sh
nsql --outDir www --files index.ts
`The above command would produce the following file:
`ts
import { uuid, timeId, timeIdms } from "@nano-sql/core/lib/interfaces";export interface ItableUsers {
id:uuid;
age:number;
name:string[];
properties?:ItypeMeta[];
address?:{
street?:string;
city?:string;
zip?:string;
state?:string;
};
[key: string]: any;
}
export interface ItypeMeta {
key:string;
value:any;
}
``