# symdb

> A JSON database that uses symbolic links for indexing

Latest version **2.3.13** (published 2022-04-25) · MIT license · 0 weekly downloads

## Install

```sh
npm install symdb
pnpm add symdb
yarn add symdb
bun add symdb
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 2.3.13 |
| Published | 2022-04-25 |
| First published | 2018-07-31 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 10 |
| Unpacked size | 99.5 KB |
| Known vulnerabilities | 0 (+1 in 1 direct dependencies) |
| Install scripts | no |
| GitHub stars | 3 |
| Author | Dan VerWeire |
| Maintainers | wankdanker |
| Keywords | json, database, symlink, symbolic, link, async, db |

## Links

- npm: https://www.npmjs.com/package/symdb
- Repository: https://github.com/wankdanker/symdb
- Homepage: https://github.com/wankdanker/symdb#readme
- Issues: https://github.com/wankdanker/symdb/issues
- npm.io page: https://npm.io/package/symdb

## Dependencies (10)

- [uuid](https://npm.io/package/uuid.md) ^8.3.2
- [extend](https://npm.io/package/extend.md) ^3.0.2
- [mkdirp](https://npm.io/package/mkdirp.md) ^0.5.1
- [dank-each](https://npm.io/package/dank-each.md) ^1.0.0
- [get-value](https://npm.io/package/get-value.md) ^3.0.1
- [set-value](https://npm.io/package/set-value.md) ^4.1.0
- [array-page](https://npm.io/package/array-page.md) ^1.3.1
- [dank-do-while](https://npm.io/package/dank-do-while.md) ^0.1.2
- [event-pipeline](https://npm.io/package/event-pipeline.md) ^2.1.0
- [fast_array_intersect](https://npm.io/package/fast_array_intersect.md) 1.1.0

## Alternatives

- [@mapbox/jsonlint-lines-primitives](https://npm.io/package/@mapbox/jsonlint-lines-primitives.md) — 5.3M weekly downloads
- [reftools](https://npm.io/package/reftools.md) — 3.5M weekly downloads
- [@hey-api/openapi-ts](https://npm.io/package/@hey-api/openapi-ts.md) — 3.5M weekly downloads
- [@mapbox/geojson-rewind](https://npm.io/package/@mapbox/geojson-rewind.md) — 2.4M weekly downloads
- [turbo-stream](https://npm.io/package/turbo-stream.md) — 1.7M weekly downloads

## Recent versions

- 2.3.13 (latest) — 2022-04-25
- 2.3.12 — 2022-04-25
- 2.3.11 — 2021-08-13
- 2.3.10 — 2021-05-24
- 2.3.9 — 2021-05-24
- 2.3.8 — 2021-05-24
- 2.3.7 — 2020-01-31
- 2.3.3 — 2019-12-30
- 2.3.1 — 2019-12-30
- 2.3.0 — 2019-12-30
- 2.2.1 — 2019-12-17
- 2.2.0 — 2019-12-17
- 2.1.3 — 2019-08-28
- 2.1.2 — 2019-04-24
- 1.9.2 — 2019-04-24
- … 18 more at https://npm.io/package/symdb/versions

## README

symdb
-----

A JSON database that uses symbolic links for indexing

reasoning
---------

There are a lot of JSON databases available on npm. Of the ones I investigated,
most store the objects for a collection in a single json file. Upon loading a
collection, the whole json file is loaded in to memory. While this is probably
the fastest method for accessing and updating objects in a collection, it could
be problematic for large collections. It also does not really lend itself to
replication in an easy way.

goals
-----

- Use the filesystem
  - each object should be stored in their own .json file
  - directories and symbolic links should be used for indexing

example
-------

```js
const SymDb = require('symdb');

const db = new SymDb({ root : './db' });

const Product = db.Model('product', {
    product_id : Number
    , name : String
    , description : String
    , type : String
});

async function go() {
    let obj = await Product.add({
        product_id : 1
        , name : 'Test'
        , type : 'test-product'
    });

    //you'll notice that the object now has a ._id attribute that is a uuid
    console.log(obj); 

    let results = await Product.get({ type : 'test-product' });

    //results is an array of objects whose type value is 'test-product'
    console.log(results);
}

go();
```

api
---

### symdb = new SymDb(opts)

* **opts.root** - string - the path to the root directory in which database files should be stored

## Model = symdb.Model(name, schema)

* **name** - string - the name of the model/collection
* **schema** - object - an object which contains `key:Type` pairs 
  * the `Types` are generally, `String`, `Number`, or some other function that will format the value to how you want it indexed. 
  * **NOTE**: this is not thoroughly tested and needs love

### Model.get(lookup[, context][, callback]) => Promise

```js
let results = Model.get({
    weight : SymDb.gt(42)
});

// also these
SymDb.gt(10)
SymDb.gte(10)
SymDb.lt(9)
SymDb.lte(9)
SymDb.startsWith('bart')
SymDb.contains('bart')
SymDb.between(1, 10)
SymDb.contains(['a','b', 'c'])
SymDb.compare(function (z) { return z === 1234 })
```
### Model.getSync(lookup[, context]) => Array

### Model.add(obj[, context][, callback]) => Promise

### Model.addSync(obj[, context][, callback]) => Object

### Model.update(obj[, context][, callback]) => Promise

### Model.updateSync(obj[, context][, callback]) => Object

### Model.del(obj[, context][, callback]) => Promise

### Model.delSync(obj[, context][, callback]) => Object

## Model Events

Example:

```js
Model.on('update:before', (event, cb) => {
    //cb must be called when done;

    event.data.password = null;

    return cb();
});
```
Callback with an error to prevent the operation from continuing 

```js
Model.on('add:before', (event, cb) => {
    if (!event.user.canAdd) {
        return cb(new Error('user does not have add permissions'));
    }

    return cb();
});

try {
    let obj = await Model.add({ href : 'https://www.google.com' }, { user : { canAdd : false } });
}
catch (e) {
    //should have thrown 'user does not have add permissions'
}
```

### Model.on('get:before', (event, cb) => {})

### Model.on('get:after', (event, cb) => {})

### Model.on('get-sync:before', (event, cb) => {})

### Model.on('get-sync:after', (event, cb) => {})

### Model.on('add:before', (event, cb) => {})

### Model.on('add:after', (event, cb) => {})

### Model.on('add-sync:before', (event, cb) => {})

### Model.on('add-sync:after', (event, cb) => {})

### Model.on('update:before', (event, cb) => {})

### Model.on('update:after', (event, cb) => {})

### Model.on('update-sync:before', (event, cb) => {})

### Model.on('update-sync:after', (event, cb) => {})

### Model.on('delete:before', (event, cb) => {})

### Model.on('delete:after', (event, cb) => {})

### Model.on('delete-sync:before', (event, cb) => {})

### Model.on('delete-sync:after', (event, cb) => {})

### Model.on('save:before', (event, cb) => {})

### Model.on('save:after', (event, cb) => {})

### Model.on('save-sync:before', (event, cb) => {})

### Model.on('save-sync:after', (event, cb) => {})

todo
----

- [ ] docs
- [ ] wildcard lookups
- [ ] case-insensitive lookups
- [ ] range lookups
- [x] lookups on non-indexed attributes
- [x] deep attribute indexing
- [ ] fulltext search
- [ ] fix cleanup of empty index directories
- [x] rewrite .update() handling to not call delete() then save()
- [x] paging
- [x] sorting
- [ ] https://github.com/davedoesdev/getdents
- [ ] automatic blob storage (Buffers, ReadStreams, SymDbFile)
  - [x] Buffers
  - [ ] Readable Streams
  - [ ] SymDbFile (a wrapper around a long string to be stored in a file outside of the json object)
  - [ ] need to handle deleting blobs on update:before
  - [ ] toggle blobs on/off per db/model
- [ ] change on-disk format to have a wrapping json object that contains metadata
  - [ ] does the object have blobs? 
  - [ ] if so, which keys?
  - [ ] keep symbolic links references in the metadata?
- [x] synchronous versions of all model operations

license
-------

MIT

---
_Source: https://npm.io/package/symdb · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
