nanoSQL 2
Universal database layer for the client, server & mobile devices. It's like Lego for databases.
Documentation | API Docs | Bugs | Chat
What is nanoSQL?
nanoSQL core provides a standardized query language, data modeling, indexing and plugin system that can use almost any database technology for data storage and query; providing a consistent experience across environments and database engines. You can mix and match database backends, query languages and plugins to get the ideal environnement for rapid development.
Multiple Database Support
Run several databases in parallel, each database can use it's own adapter. This means you could have one nanoSQL instance running a Redis based database, a MySQL based database and a RocksDB based database at the same time seamlessly!
Identical API Everywhere
Develop your application with an embedded database like RocksDB, then deploy into production with Redis, Amazon Dynamo, MySQL or many others. NanoSQL even runs in the browser on top of IndexedDB, WebSQL or LocalStorage. All data is portable and all features are isomorphic; jumping between different databases and environments is trivial.
Not Only NoSQL
Classical RDBMS queries like aggregate functions, joins and group bys are also supported. You can even write your own query functions and use foreign keys!
Flexible Data Models
The best of both worlds: Use RDBMS style data models to tune performance but still allow arbitrary columns. Change your data model as often as you want and do type casting only when you need it.
Data Models => TypeScript Files
Instantly convert data models into typescript interfaces.
Graph Queries
Use indexing to build nested graph queries on your data with the power of RDBMS and flexibility of noSQL.
Other Cool Things
Built in geolocation indexing, autocomplete, observable queries, typescript support, event system, CSV/JSON import & export, runs in every browser back to IE9 and starts at only 30KB!
Comparison with Other Projects
| nanoSQL | TaffyDB | NeDB | LoveField | PouchDB | alaSQL | RxDB | SQL.js | Lunr |
---|
Events | ✓ | ✓ | ✕ | ✓ | ✓ | ✕ | ✓ | ✕ | ✕ |
Typescript | ✓ | ✕ | ✓ | ✓ | ✓ | ✕ | ✓ | ✓ | ✓ |
Graph Queries | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ |
Join Queries | ✓ | ✓ | ✓ | ✓ | ✕ | ✓ | ✕ | ✓ | ✕ |
IndexedDB | ✓ | ✕ | ✕ | ✓ | ✓ | ✓ | ✓ | ✕ | ✕ |
NodeJS | ✓ | ✓ | ✓ | ✕ | ✓ | ✓ | ✓ | ✓ | ✓ |
Foreign Keys | ✓ | ✕ | ✕ | ✓ | ✕ | ✓ | ✕ | ✓ | ✕ |
Query Functions | ✓ | ✕ | ✕ | ✕ | ✕ | ✓ | ✕ | ✓ | ✕ |
Custom Backends | ✓ | ✕ | ✕ | ✕ | ✓ | ✕ | ✓ | ✕ | ✕ |
Size (kb) | 30 | 5 | 27 | 40 | 46 | 88 | 164 | 500 | 8 |
Database Support
NanoSQL can save data to many different places, depending on the browser or environment it's being ran in.
-
Included In The Box
- Memory (Browser/NodeJS/Electron)
- Snap DB (NodeJS/Electron)
- Indexed DB (Browser)
- WebSQL (Browser)
- Local Storage (Browser)
-
RocksDB (NodeJS/Electron)
-
LevelDB (NodeJS/Electron)
-
SQLite (NodeJS/Electron)
-
SQLite (Cordova)
-
SQLite (NativeScript)
-
React Native
-
Redis
-
MySQL
-
Amazon Dynamo DB
-
MongoDB
-
ScyllaDB
Plugins
Installation
npm i @nano-sql/core --save
Using in Typescript/Babel project:
import { nSQL } from "@nano-sql/core";
Using in Node:
const nSQL = require("@nano-sql/core").nSQL;
To use directly in the browser, drop one of the tags below into your <head>
.
<script src="https://cdn.jsdelivr.net/npm/@nano-sql/core@2.3.3/dist/nano-sql.min.js" integrity="sha256-rMu9OODIi1wTkpKMdSY8rbmelYOo3/uoGohEZDbHaVU=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@nano-sql/core@2.3.3/dist/nano-sql.min.es5.js" integrity="sha256-1sHMq8+9Zy1Qk+egrnjU151TOx43wsTQy/oX4g7fNs8=" crossorigin="anonymous"></script>
Important
If you are migrating from nanoSQL 1.X to 2.X, please read the migration guide.
Query Examples
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);
});
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);
});
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);
})
CLI
The nanoSQL command line interface allows you to compile data models into typescript interface files.
Usage is as follows:
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:
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}
}
}
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:
nsql --outDir www --files index.ts
The above command would produce the following file:
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;
}
2.0 Progress