Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

lowdb

Package Overview
Dependencies
Maintainers
1
Versions
76
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

lowdb - npm Package Compare versions

Comparing version 1.0.0 to 2.0.0

.commitlintrc.json

110

examples/README.md

@@ -6,21 +6,21 @@ # Examples

```js
const low = require('lowdb')
const FileSync = require('lowdb/adapters/FileSync')
// cli.js
import { LowSync, JSONFileSync } from 'lowdb'
const adapter = new FileSync('db.json')
const db = low(adapter)
const title = process.argv[2]
const adapter = new FileSync('file.json')
const db = new LowSync(adapter)
db.defaults({ posts: [] })
.write()
db.read()
db.data ||= { posts: [] }
const result = db.get('posts')
.push({ name: process.argv[2] })
.write()
db.data.posts.push({ title })
console.log(result)
db.write()
```
```sh
$ node cli.js hello
# [ { title: 'hello' } ]
$ node cli.js "hello world"
$ cat file.json
# { "posts": [ "title": "hello world" ] }
```

@@ -31,15 +31,13 @@

```js
import low from 'lowdb'
import LocalStorage from 'lowdb/adapters/LocalStorage'
import { LowSync, LocalStorage } from 'lowdb'
const adapter = new LocalStorage('db')
const db = low(adapter)
const db = new LowSync(adapter)
db.defaults({ posts: [] })
.write()
db.read()
db.data ||= { posts: [] }
// Data is automatically saved to localStorage
db.get('posts')
.push({ title: 'lowdb' })
.write()
db.data.posts.push({ title: 'lowdb' })
db.write()
```

@@ -49,44 +47,34 @@

Please __note__ that if you're developing a local server and don't expect to get concurrent requests, it's often easier to use `file-sync` storage, which is the default.
**Note** if you're developing a local server and don't expect to get concurrent requests, it can be easier to use `JSONFileSync` adapter.
But if you need to avoid blocking requests, you can do so by using `file-async` storage.
But if you need to avoid blocking requests, you can do so by using `JSONFile` adapter.
```js
const express = require('express')
const low = require('lowdb')
const FileAsync = require('lowdb/adapters/FileAsync')
import express from 'express'
import { Low, JSONFile } from 'lowdb'
// Create server
const app = express()
app.use(express.json())
// Routes
// GET /posts/:id
app.get('/posts/:id', (req, res) => {
const post = db.get('posts')
.find({ id: req.params.id })
.value()
const adapter = new JSONFile('db.json')
const db = new Low(adapter)
await db.read()
db.data ||= { posts: [] }
const { posts } = db.data
app.get('/posts/:id', async (req, res) => {
const post = posts.find((p) => p.id === req.params.id)
res.send(post)
})
// POST /posts
app.post('/posts', (req, res) => {
db.get('posts')
.push(req.body)
.last()
.assign({ id: Date.now() })
.write()
.then(post => res.send(post))
app.post('/posts', async (req, res, next) => {
const post = posts.push(req.body)
await db.write()
res.send(post)
})
// Create database instance and start server
const adapter = new FileAsync('db.json')
low(adapter)
.then(db => {
db.defaults({ posts: [] })
.write()
})
.then(() => {
app.listen(3000, () => console.log('listening on port 3000')
})
app.listen(3000, () => {
console.log('listening on port 3000')
})
```

@@ -100,18 +88,10 @@

const fs = require('fs')
const low = require('low')
const FileSync = require('low/adapters/FileSync')
const Memory = require('low/adapters/Memory')
const low = require('lowdb/lib/LowSync')
const FileSync = require('lowdb/lib/adapters/FileSync')
const MemorySync = require('lowdb/lib/adapters/MemorySync')
const db = low(
process.env.NODE_ENV === 'test'
? new Memory()
: new FileSync('db.json')
)
const adapter =
process.env.NODE_ENV === 'test' ? new MemorySync() : new FileSync('db.json')
db.defaults({ posts: [] })
.write()
db.get('posts')
.push({ title: 'lowdb' })
.write()
const db = new LowSync(adapter)
```
{
"name": "lowdb",
"version": "1.0.0",
"description": "Small JSON database for Node, Electron and the browser. Powered by Lodash.",
"version": "2.0.0",
"description": "Tiny local JSON database for Node, Electron and the browser",
"type": "module",
"exports": "./lib/index.js",
"directories": {
"example": "examples"
},
"scripts": {
"test": "jest --config .jestrc.json",
"lint": "eslint src --ext .ts --ignore-path .gitignore",
"build": "del-cli lib && tsc",
"prepublishOnly": "npm run build",
"postversion": "git push && git push --tags && npm publish",
"prepare": "husky install"
},
"repository": {
"type": "git",
"url": "git+https://github.com/typicode/lowdb.git"
},
"keywords": [
"flat",
"file",
"local",
"database",
"storage",
"JSON",
"lodash",
"localStorage",
"electron",
"embed",
"embeddable"
"embedded",
"flat",
"JSON",
"local",
"localStorage"
],
"main": "./lib/main.js",
"scripts": {
"test": "jest && npm run lint",
"lint": "eslint . --ignore-path .gitignore",
"fix": "npm run lint -- --fix",
"prepublishOnly": "npm run build && pkg-ok",
"build": "npm run build:lib && npm run build:dist",
"build:lib": "rimraf lib && babel src --out-dir lib && npm run mvAdapters",
"build:dist": "rimraf dist && webpack && webpack -p",
"mvAdapters": "rimraf adapters && mv lib/adapters .",
"precommit": "npm test"
},
"repository": {
"type": "git",
"url": "git://github.com/typicode/lowdb.git"
},
"author": "Typicode <typicode@gmail.com>",
"license": "MIT",
"license": "Parity-7.0.0 AND MIT WITH Patron-1.0.0",
"bugs": {
"url": "https://github.com/typicode/lowdb/issues"
},
"homepage": "https://github.com/typicode/lowdb",
"homepage": "https://github.com/typicode/lowdb#readme",
"devDependencies": {
"@commitlint/cli": "^12.0.1",
"@commitlint/config-conventional": "^12.0.1",
"@commitlint/prompt-cli": "^12.0.1",
"@tsconfig/node12": "^1.0.7",
"@types/jest": "^26.0.20",
"@types/lodash": "^4.14.168",
"@types/node": "^15.0.3",
"@typicode/eslint-config": "^0.1.0",
"del-cli": "^3.0.1",
"husky": "^6.0.0",
"jest": "^26.6.3",
"jest-localstorage-mock": "^2.4.8",
"lodash": "^4.17.21",
"tempy": "^1.0.1",
"ts-jest": "^26.5.3",
"typescript": "^4.2.3"
},
"dependencies": {
"graceful-fs": "^4.1.3",
"is-promise": "^2.1.0",
"lodash": "4",
"pify": "^3.0.0",
"steno": "^0.4.1"
"steno": "^1.0.0"
},
"devDependencies": {
"babel-cli": "^6.2.0",
"babel-eslint": "^7.0.0",
"babel-jest": "^20.0.3",
"babel-loader": "^7.1.1",
"babel-polyfill": "^6.9.1",
"babel-preset-env": "^1.6.0",
"babel-register": "^6.9.0",
"delay": "^2.0.0",
"eslint": "^4.5.0",
"eslint-config-prettier": "^2.3.0",
"eslint-config-standard": "^10.2.1",
"eslint-plugin-import": "^2.6.1",
"eslint-plugin-node": "^5.1.0",
"eslint-plugin-prettier": "^2.1.2",
"eslint-plugin-promise": "^3.5.0",
"eslint-plugin-standard": "^3.0.1",
"husky": "^0.14.3",
"jest": "^20.0.4",
"lodash-id": "^0.14.0",
"mv": "^2.1.1",
"pkg-ok": "^1.0.1",
"prettier": "^1.5.2",
"ramda": "^0.24.1",
"regenerator-runtime": "^0.11.0",
"rimraf": "^2.5.4",
"sinon": "^3.2.1",
"tempfile": "^2.0.0",
"webpack": "^3.3.0"
},
"engines": {
"node": ">=4"
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
}
}

@@ -1,75 +0,46 @@

# Lowdb
# lowdb
[![](http://img.shields.io/npm/dm/lowdb.svg?style=flat)](https://www.npmjs.org/package/lowdb) [![NPM version](https://badge.fury.io/js/lowdb.svg)](http://badge.fury.io/js/lowdb) [![Build Status](https://travis-ci.org/typicode/lowdb.svg?branch=master)](https://travis-ci.org/typicode/lowdb) [![Donate](https://img.shields.io/badge/patreon-donate-ff69b4.svg)](https://www.patreon.com/typicode)
> Tiny local JSON database for small projects 🦉
> Small JSON database for Node, Electron and the browser. Powered by Lodash. :zap:
```js
db.get('posts')
.push({ id: 1, title: 'lowdb is awesome'})
.write()
db.data.posts.push({ id: 1, title: 'lowdb is awesome' })
db.write()
```
## Usage
```sh
npm install lowdb
```js
// db.json
{
"posts": [
{ "id": 1, "title": "lowdb is awesome" }
]
}
```
```js
const low = require('lowdb')
const FileSync = require('lowdb/adapters/FileSync')
## Free for Open Source
const adapter = new FileSync('db.json')
const db = low(adapter)
To help with OSS funding, lowdb v2 is released under Parity license for a limited time. It'll be released under MIT license once the __goal of 100 [sponsors](https://github.com/sponsors/typicode)__ is reached (currently at 55) or in five months.
// Set some defaults
db.defaults({ posts: [], user: {} })
.write()
Meanwhile, lowdb v2 can be freely used in Open Source projects. Sponsors can use it in any type of project.
// Add a post
db.get('posts')
.push({ id: 1, title: 'lowdb is awesome'})
.write()
If you've installed this new version without knowing about the license change, you're excused for 30 days. There's also a 30 days trial. See license files for more details.
// Set a user using Lodash shorthand syntax
db.set('user.name', 'typicode')
.write()
```
Thank you for your support!
Data is saved to `db.json`
__Note:__ if you're already sponsoring [husky](https://github.com/typicode/husky), you can use lowdb v2 today :)
```json
{
"posts": [
{ "id": 1, "title": "lowdb is awesome"}
],
"user": {
"name": "typicode"
}
}
```
## Companies
You can use any [lodash](https://lodash.com/docs) function like [`_.get`](https://lodash.com/docs#get) and [`_.find`](https://lodash.com/docs#find) with shorthand syntax.
[Become a sponsor and have your company logo here](https://github.com/sponsors/typicode).
```js
// Use .value() instead of .write() if you're only reading from db
db.get('posts')
.find({ id: 1 })
.value()
```
## Features
Lowdb is perfect for CLIs, small servers, Electron apps and npm packages in general.
- __Lightweight__
- __Minimalist__ and easy to learn API
- Query and modify data using __plain JS__
- Improved __TypeScript__ support
- Atomic write
- Hackable:
- Change storage, file format (JSON, YAML, ...) or add encryption via [adapters](#adapters)
- Add lodash, ramda, ... for super powers!
It supports __Node__, the __browser__ and uses __lodash API__, so it's very simple to learn. Actually, if you know Lodash, you already know how to use lowdb :wink:
* [Usage examples](https://github.com/typicode/lowdb/tree/master/examples)
* [CLI](https://github.com/typicode/lowdb/tree/master/examples#cli)
* [Browser](https://github.com/typicode/lowdb/tree/master/examples#browser)
* [Server](https://github.com/typicode/lowdb/tree/master/examples#server)
* [In-memory](https://github.com/typicode/lowdb/tree/master/examples#in-memory)
* [JSFiddle live example](https://jsfiddle.net/typicode/4kd7xxbu/)
__Important__ lowdb doesn't support Cluster and may have issues with very large JSON files (~200MB).
## Install

@@ -81,304 +52,232 @@

Alternatively, if you're using [yarn](https://yarnpkg.com/)
## Usage
```sh
yarn add lowdb
```
```js
import { join } from 'path'
import { Low, JSONFile } from 'lowdb'
A UMD build is also available on [unpkg](https://unpkg.com/) for testing and quick prototyping:
// Use JSON file for storage
const file = join(__dirname, 'db.json')
const adapter = new JSONFile(file)
const db = new Low(adapter)
```html
<script src="https://unpkg.com/lodash@4/lodash.min.js"></script>
<script src="https://unpkg.com/lowdb@0.17/dist/low.min.js"></script>
<script src="https://unpkg.com/lowdb@0.17/dist/LocalStorage.min.js"></script>
<script>
var adapter = new LocalStorage('db')
var db = low(adapter)
</script>
```
// Read data from JSON file, this will set db.data content
await db.read()
## API
// If file.json doesn't exist, db.data will be null
// Set default data
db.data ||= { posts: [] }
__low(adapter)__
// Create and query items using plain JS
db.data.posts.push('hello world')
db.data.posts[0]
Returns a lodash [chain](https://lodash.com/docs/4.17.4#chain) with additional properties and functions described below.
// You can also use this syntax if you prefer
const { posts } = db.data
posts.push('hello world')
__db.[...].write()__
// Write db.data content to db.json
await db.write()
```
__db.[...].value()__
```js
// db.json
{
"posts": [ "hello world" ]
}
```
`write()` is syntactic sugar for calling `value()` and `db.write()` in one line.
### TypeScript
On the other hand, `value()` is just [\_.protoype.value()](https://lodash.com/docs/4.17.4#prototype-value) and should be used to execute a chain that doesn't change database state.
Lowdb now comes with TypeScript support. You can even type `db.data` content.
```ts
type Data = {
posts: string[] // Expect posts to be an array of strings
}
const db = new Low<Data>(adapter)
```js
db.set('user.name', 'typicode')
.write()
// is equivalent to
db.set('user.name', 'typicode')
.value()
db.write()
db.data
.posts
.push(1) // TypeScript error 🎉
```
__db.___
### Lodash
Database lodash instance. Use it to add your own utility functions or third-party mixins like [underscore-contrib](https://github.com/documentcloud/underscore-contrib) or [lodash-id](https://github.com/typicode/lodash-id).
You can easily add lodash or other utility libraries to improve lowdb.
```js
db._.mixin({
second: function(array) {
return array[1]
}
})
import lodash from lodash
db.get('posts')
.second()
// ...
// Note: db.data needs to be initialized before lodash.chain is called.
db.chain = lodash.chain(db.data)
// Instead of db.data, you can now use db.chain if you want to use the powerful API that lodash provides
const post = db.chain
.get('posts')
.find({ id: 1 })
.value()
```
__db.getState()__
### More examples
Returns database state.
For CLI, server and browser usage, see [`examples/`](/examples) directory.
```js
db.getState() // { posts: [ ... ] }
```
## API
__db.setState(newState)__
### Classes
Replaces database state.
Lowdb has two classes (for asynchronous and synchronous adapters).
```js
const newState = {}
db.setState(newState)
```
#### `new Low(adapter)`
__db.write()__
Persists database using `adapter.write` (depending on the adapter, may return a promise).
```js
// With lowdb/adapters/FileSync
db.write()
console.log('State has been saved')
import { Low, JSONFile } from 'lowdb'
// With lowdb/adapters/FileAsync
db.write()
.then(() => console.log('State has been saved'))
const db = new Low(new JSONFile('file.json'))
await db.read()
await db.write()
```
__db.read()__
#### `new LowSync(adapterSync)`
Reads source using `storage.read` option (depending on the adapter, may return a promise).
```js
import { LowSync, JSONFileSync } from 'lowdb'
```js
// With lowdb/FileSync
const db = new LowSync(new JSONFileSync('file.json'))
db.read()
console.log('State has been updated')
// With lowdb/FileAsync
db.write()
.then(() => console.log('State has been updated'))
```
## Adapters API
### Methods
Please note this only applies to adapters bundled with Lowdb. Third-party adapters may have different options.
#### `db.read()`
For convenience, `FileSync`, `FileAsync` and `LocalBrowser` accept the following options:
Calls `adaper.read()` and sets `db.data`.
* __defaultValue__ if file doesn't exist, this value will be used to set the initial state (default: `{}`)
* __serialize/deserialize__ functions used before writing and after reading (default: `JSON.stringify` and `JSON.parse`)
**Note:** `JSONFile` and `JSONFileSync` adapters will set `db.data` to `null` if file doesn't exist.
```js
const adapter = new FileSync('array.yaml', {
defaultValue: [],
serialize: (array) => toYamlString(array),
deserialize: (string) => fromYamlString(string)
})
db.data // === null
db.read()
db.data // !== null
```
## Guide
#### `db.write()`
### How to query
Calls `adapter.write(db.data)`.
With lowdb, you get access to the entire [lodash API](http://lodash.com/), so there are many ways to query and manipulate data. Here are a few examples to get you started.
Please note that data is returned by reference, this means that modifications to returned objects may change the database. To avoid such behaviour, you need to use `.cloneDeep()`.
Also, the execution of methods is lazy, that is, execution is deferred until `.value()` or `.write()` is called.
#### Examples
Check if posts exists.
```js
db.has('posts')
.value()
db.data = { posts: [] }
db.write() // file.json will be { posts: [] }
db.data = {}
db.write() // file.json will be {}
```
Set posts.
### Properties
```js
db.set('posts', [])
.write()
```
#### `db.data`
Holds your db content. If you're using the adapters coming with lowdb, it can be any type supported by [`JSON.stringify`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify).
Sort the top five posts.
For example:
```js
db.get('posts')
.filter({published: true})
.sortBy('views')
.take(5)
.value()
db.data = 'string'
db.data = [1, 2, 3]
db.data = { key: 'value' }
```
Get post titles.
## Adapters
```js
db.get('posts')
.map('title')
.value()
```
### Lowdb adapters
Get the number of posts.
#### `JSONFile` `JSONFileSync`
Adapters for reading and writing JSON files.
```js
db.get('posts')
.size()
.value()
new Low(new JSONFile(filename))
new LowSync(new JSONFileSync(filename))
```
Get the title of first post using a path.
#### `Memory` `MemorySync`
```js
db.get('posts[0].title')
.value()
```
In-memory adapters. Useful for speeding up unit tests.
Update a post.
```js
db.get('posts')
.find({ title: 'low!' })
.assign({ title: 'hi!'})
.write()
new Low(new Memory())
new LowSync(new MemorySync())
```
Remove posts.
#### `LocalStorage`
```js
db.get('posts')
.remove({ title: 'low!' })
.write()
```
Synchronous adapter for `window.localStorage`.
Remove a property.
```js
db.unset('user.name')
.write()
new LowSync(new LocalStorage())
```
Make a deep clone of posts.
### Third-party adapters
```js
db.get('posts')
.cloneDeep()
.value()
```
If you've published an adapter for lowdb, feel free to create a PR to add it here.
### How to use id based resources
### Writing your own adapter
Being able to get data using an id can be quite useful, particularly in servers. To add id-based resources support to lowdb, you have 2 options.
You may want to create an adapter to write `db.data` to YAML, XML, ... or encrypt data.
[shortid](https://github.com/dylang/shortid) is more minimalist and returns a unique id that you can use when creating resources.
An adapter is a simple class that just needs to expose two methods:
```js
const shortid = require('shortid')
class AsyncAdapter {
read() { /* ... */ } // should return Promise<data>
write(data) { /* ... */ } // should return Promise<void>
}
const postId = db
.get('posts')
.push({ id: shortid.generate(), title: 'low!' })
.write()
.id
const post = db
.get('posts')
.find({ id: postId })
.value()
class SyncAdapter {
read() { /* ... */ } // data
write(data) { /* ... */ } // void
}
```
[lodash-id](https://github.com/typicode/lodash-id) provides a set of helpers for creating and manipulating id-based resources.
For example, let's say you have some async storage and want to create an adapter for it:
```js
const lodashId = require('lodash-id')
const db = low('db.json')
import { api } from './AsyncStorage'
db._.mixin(lodashId)
const post = db
.get('posts')
.insert({ title: 'low!' })
.write()
const post = db
.get('posts')
.getById(post.id)
.value()
```
### How to create custom adapters
`low()` accepts custom Adapter, so you can virtually save your data to any storage using any format.
```js
class MyStorage {
constructor() {
class CustomAsyncAdapter {
// Optional: your adapter can take arguments
constructor(args) {
// ...
}
read() {
// Should return data (object or array) or a Promise
async read() {
const data = await api.read()
return data
}
write(data) {
// Should return nothing or a Promise
async write(data) {
await api.write(data)
}
}
const adapter = new MyStorage(args)
const db = low()
const adapter = new CustomAsyncAdapter()
const db = new Low(adapter)
```
See [src/adapters](src/adapters) for examples.
See [`src/adapters/`](src/adapters) for more examples.
### How to encrypt data
## Limits
`FileSync`, `FileAsync` and `LocalStorage` accept custom `serialize` and `deserialize` functions. You can use them to add encryption logic.
Lowdb doesn't support Node's cluster module.
```js
const adapter = new FileSync('db.json', {
serialize: (data) => encrypt(JSON.stringify(data))
deserialize: (data) => JSON.parse(decrypt(data))
})
```
If you have large JavaScript objects (`~10-100MB`) you may hit some performance issues. This is because whenever you call `db.write`, the whole `db.data` is serialized and written to storage.
## Changelog
Depending on your use case, this can be fine or not. It can be mitigated by doing batch operations and calling `db.write` only when you need it.
See changes for each version in the [release notes](https://github.com/typicode/lowdb/releases).
If you plan to scale, it's highly recommended to use databases like PostgreSQL, MongoDB, ...
## Limits
Lowdb is a convenient method for storing data without setting up a database server. It is fast enough and safe to be used as an embedded database.
However, if you seek high performance and scalability more than simplicity, you should probably stick to traditional databases like MongoDB.
## License
MIT - [Typicode :cactus:](https://github.com/typicode)
[License Zero Parity 7.0.0](https://paritylicense.com/versions/7.0.0.html) and MIT (contributions) with exception [License Zero Patron 1.0.0](https://patronlicense.com/versions/1.0.0).

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc