# Gun-Flint: Easy Gun Adapters

Gun-Flint is a package that makes it easy to write adapters to connect your Gun database to various services (like databases, Pusher, etc.). Gun-Flint is not itself an adapter.

# Installation

`npm install gun-flint`

or 

`yarn add gun-flint`

# A Key Decision: Node, Key:Value, Delta

Since Gun is a graph database, its data structure requires some special consideration. Gun-Flint attempts to provide as much flexibility for the adapter developer to store data in a format that makes sense for the storage system you are using.

Building your Gun-Flint gives you an advantage of allowing Flint to ensure that the data coming from Gun reaches your adapter in a consistent format and returns data to Gun in a format that it recognizes.

### [Node Storage](https://github.com/sjones6/gun-flint/blob/master/docs/NODE_ADAPTER.MD)

`get` request expect to read an entire Gun node; `put` requests write an entire node.

Pros: 
* Easiest to implement
* Flint handles merging of existing nodes with a delta on write so little chance of data corruption during conflict resolution.

Cons:
* Slower performance (requires a read > merge for every write); this is especially problematic if your data requires large nodes (e.g., a `users` node with millions of `user`s)
* Large nodes could overwhelm memory and cause crashes; if you anticipate this, consider [Key:Value](https://github.com/sjones6/gun-flint/blob/master/docs/KEY_VAL_ADAPTER.MD) storage with streaming.

**When to Use:** Most/all nodes are small; nodes are frequently created; optimal for document-based databases (e.g., MongoDB; Postgres)

Example: [gun-mongo](https://github.com/sjones6/gun-mongo)

### [Key:Value](https://github.com/sjones6/gun-flint/blob/master/docs/KEY_VAL_ADAPTER.MD)

`get` request returns an array/list of nodes properties; `put` requests write batch updates to specific node's key:value pairs.

Pros: 
* Easy to implement
* Faster than full-node storage
* Doesn't require any additional concerns for conflict resolution

Cons:
* Every key:value pair (node property) would presumably require a separate record in storage (although not necessarily)
* Read requests require retrieval of multiple records

**When to Use:** Nodes are small/medium in size; some large nodes; nodes are frequently updated

Example: [gun-mongo-key](https://github.com/sjones6/gun-mongo-key)

### [Delta Storage](https://github.com/sjones6/gun-flint/blob/master/docs/DELTA_ADAPTER.MD)

`get` request return an entire node, formatted in a way Gun recognizes; `put` requests receive a delta (diff) of node properties as well as conflict-resolution state indicators.

Pros:
* Most flexibility for how you store a delta
* High performance possibility, depending on how you implement storage.

Cons:
* Most difficult to implement, and incorrect implementation can lead to data corruption during conflict resolution.

**When to Use:** You need total control of storage format and one of the above formats is not sufficient.

# Usage

Whichever storage method you decide, your adapter needs to only implement three methods: opt, get, put. See the documentation for each storage method as the exact API depends on the method selected.

Stripped down, the API looks like this:
```javascript

const {Flint, NodeAdapter} = require('gun-flint');

const myGunAdapter = new NodeAdapter({
    opt: function(context, options) {
        // etc
    },
    get: function(key, field, done) {
        // handle read
    },
    put: function(node, done) {
        // handle write
    }
});

Flint.register(myGunAdapter);
```

# Using Your Adapter

In the end, the good users of your adapter should install it like this:

```javascript

var Gun = require('gun');

// Adapter must come after requiring Gun but before `new Gun`
require('your-awesome-adapter');

// Adapters all set up? Instantiate Gun.
var gun = new Gun({
    myAwesomeAdapter: {
        key: "This gets passed into the `opt` call when gun is initialized. Useful for allowing those who use your adapter to pass in DB drivers of the like."
    }
});
```

# Testing Your Adapter

Flint comes packaged with an integration testing suite. See [full documentation here](https://github.com/sjones6/gun-flint/blob/master/docs/INTEGRATION_TESTING.MD).

# Performance Profiling

Flint comes packaged with an performance suite that will run against your adapter. See [full documentation here](https://github.com/sjones6/gun-flint/blob/master/docs/PERFORMANCE_TESTING.MD).

# Troubleshooting

If your adapter's `opt` function is never called, or when it is called, it doesn't have options that you passed to the constructor, here are some steps:

1. Do NOT list Gun in your list of dependencies. You can list it in `peerDependencies` or `devDependencies`, especially the later if you need it for testing your adapter.
2. Make sure Gun is not installed globally (run `npm list -g --depth=0` to check), and `npm uninstall -g gun` if it is.
3. Delete your `node_modules` and install a fresh set (preferably from a lockfile)