Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redisqlite #7

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: Node.js CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [10.x, 12.x, 14.x, 15.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm test
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,14 @@ async function main(args) {
// Database (MySQL)
const db = await nim.mysql(); // Returns a configured mysql2 connection.
const [rows, fields] = await db.execute('SELECT * FROM `table`');

// Embedded Database (SQLite)
const sql = nim.sqlite()
}
```

Check [esql](SQLITE.md) for Embedded SQL api documentation.

## Support

We're always happy to help you with any issues you encounter. You may want to [join our Slack community](https://nimbella-community.slack.com/) to engage with us for a more rapid response.
Expand Down
87 changes: 87 additions & 0 deletions SQLITE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Embedded SQL Database

You can access embedded sql with:

```
let nim = require("@nimbella/sdk")
const sql = nim.esql()
```

Available methods are:

- `exec(args)` args either string or array

You can execute a statement:

```
let res = await sql.exec("create table t(i int)")
```

It returns a promise of `[lastId, changedRows]`.
Values are significant where relevant (for insert or delete but not for create for example).

You can also execute a parametric statement and specify parameters passing an array as first argument:

```
res = await sql.exec(["insert into t(i) values(?)",1])
```

- `map(args [,limit])`, `args` either string or array, `limit` a number

You can execute a query, getting an array of objects.

```
let m = await sql.map("select * from t")
```

In the result each object corresponds to a record: `[{i:1},{i:2}]` where the keys are the field names, and the values the field values.

You can also pass parameters using an array as first argument, and limit the number of returned elements with an integer as second argument:

```
m = await sql.map(["select * from t where i >?",],1)
```

Result: `[{i:1}]`

- `arr(args [,limit])`, `args` either string or array, `limit` a number

You can execute a query, getting an array of arrays.
Each element in the array corresponds to an array of the record values.

```
let m = await sql.map("select * from t")
```
Result: `[[1],[2]]`

You can also pass parameters using an array as first argument, and limit the number of returned elements with an integer as second argument:

```
m = await sql.map(["select * from t where i >?",],1)
```
Result: `[[1]]`

- `prep(arg)` where `arg` is either a string or a numer

You can prepare statements to save time from precompiling.

```
let ins = await sql.prep("insert into t(i) values(?)")
let sel = await sql.prep("select * from t where i>?")
```

The returned value is a number and can be used to execute the statement with `exec`, `map` and `arr`.

```
res = await sql.exec([ins,1])
m = await sql.map([sel,1],1)
```

When you do not need any more you can close the statement running prep again with the returned value.

```
await sql.prep(ins)
await sql.prep(sel)
```

Note that you can prepare up to 10000 statement at the same time without closing them, otherwise you will get an error `too many prepared statement`. In the unfortunate accident you fill the cache, you can clear it with `prep("clean_prep_cache")`
12 changes: 10 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
var redis = require('redis');
var bluebird = require('bluebird');
const { getStorageProvider } = require('@nimbella/storage');
const Redisqlite = require("./redisqlite.js")

function makeRedisClient() {
bluebird.promisifyAll(redis.RedisClient.prototype);
Expand All @@ -29,7 +30,7 @@ function makeRedisClient() {
if (!redisPassword || redisPassword.length == 0) {
throw new Error('Key-Value store password is not available');
}
const redisParam = {port: 6379, host: redisHost};
const redisParam = { port: 6379, host: redisHost };
const client = redis.createClient(redisParam);
if (client == null) {
throw new Error('Error creating redis client');
Expand Down Expand Up @@ -96,11 +97,18 @@ async function makeSqlClient() {
});
}


function makeSqliteClient() {
let client = makeRedisClient()
sciabarracom marked this conversation as resolved.
Show resolved Hide resolved
sciabarracom marked this conversation as resolved.
Show resolved Hide resolved
return new Redisqlite(client)
}

module.exports = {
redis: makeRedisClient,
// Legacy function, returns Promise<Bucket>
storage: legacyMakeStorageClient,
// New version of the function, returns the more abstract type StorageClient
storageClient: makeStorageClient,
mysql: makeSqlClient
mysql: makeSqlClient,
esql: makeSqliteClient
};
11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"lambda"
],
"files": [
"index.js"
"index.js",
"redisqlite.js"
],
"repository": {
"type": "git",
Expand All @@ -28,5 +29,13 @@
"bluebird": "^3.7.2",
"mysql2": "^2.1.0",
"redis": "^3.0.2"
},
"scripts": {
"start": "docker run -d -p 6379:6379 --rm --name redisqlite sciabarracom/redisqlite:v1.0.4 --requirepass password",
"test": "npm run start ; jest ; npm run stop",
"stop": "docker kill redisqlite"
sciabarracom marked this conversation as resolved.
Show resolved Hide resolved
},
"devDependencies": {
"jest": "^26.6.3"
}
}
87 changes: 87 additions & 0 deletions redisqlite.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* Copyright (c) 2020-present, Nimbella, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

function Redisqlite(redis) {
this.redis = redis
}

Redisqlite.prototype.exec = function (sql) {
if (!Array.isArray(sql))
sql = [sql]
const redis = this.redis
return new Promise(function (resolve, reject) {
redis.send_command("SQLEXEC", sql,
function (err, res) {
if (err)
reject(err)
else
resolve(res.map(JSON.parse))
})
})
}

Redisqlite.prototype.prep = function (sql) {
const redis = this.redis
if (!Array.isArray(sql))
sql = [sql]
return new Promise(function (resolve, reject) {
redis.send_command("SQLPREP", sql,
function (err, res) {
if (err)
reject(err)
else
resolve(res)
})
})
}

Redisqlite.prototype.map = function (sql, count) {
if(count === undefined)
count = 0
if (!Array.isArray(sql))
sql = [sql]
sql.unshift(count)
const redis = this.redis
return new Promise(function (resolve, reject) {
redis.send_command("SQLMAP", sql,
function (err, res) {
if (err)
reject(err)
else
resolve(res.map(JSON.parse))
})
})
}

Redisqlite.prototype.arr = function (sql, count) {
if(count === undefined)
count = 0
if (!Array.isArray(sql))
sql = [sql]
sql.unshift(count)
const redis = this.redis
return new Promise(function (resolve, reject) {
redis.send_command("SQLARR", sql,
function (err, res) {
if (err)
reject(err)
else
resolve(res.map(JSON.parse))
})
})
}

module.exports = Redisqlite
Loading