const faunadb = require('faunadb')
/**
* A wrapper class for using the faunuDB javascript API
*/
class FaunaConnection {
constructor(options) {
const { secret } = options
this.q = faunadb.query
this.client = new faunadb.Client({ secret })
this.size = 64;
}
/**
* If the client was instantiated using an admin key
* this will create a database with the given name.
*
* @param {string} name the name to use for the database
* @return {Object} Response object with database name and ref
*/
createDB(name) {
return this.client.query(
this.q.CreateDatabase({ name: name })
)
}
/**
* If the client was instantiated with at least a
* databse key, this will return a server role for
* the given named database.
*
* @param {string} dbName the name of the database to create a server for
* @return {Object} Response object with database name and ref
*/
createServer(dbName) {
return this.client.query(
this.q.CreateKey({
database: this.q.Database(dbName),
role: 'server'
})
)
}
/**
* Creates a collection of the given name
*
* @param {string} name A descriptive name for the collection
* @return {Object} Reference to collection object
*/
createCollection(name) {
return this.client.query(
this.q.CreateCollection({ name: name})
)
}
/**
* Creates an index for use on a collection
*
* @param {string} name descriptive name for the index
* @param {string} src the name of the collection to apply this to
* @param {Array} terms the terms to be used for the index
* @param {Array} values the values to be used for the index
* @return {Object} the index object
*/
createIndex(name, src, terms=null, values=null) {
return this.client.query(
this.q.CreateIndex({
name: name,
source: this.q.Collection(src),
terms: terms,
values: values
})
)
}
/**
* Creates a document within the named collection given either single doc
* or an array of documents.
* @param {string} collection name of the collection to put the doc into
* @param {Object} doc the document to put in the database collection
* @return {Object} the document that was inserted
*/
create(collection, docs) {
const documents = Array.isArray(docs) ? docs : [docs]
return this.client.query(
this.q.Map(
documents,
this.q.Lambda(
'doc',
this.q.Create(
this.q.Collection(collection),
{ data: this.q.Var('doc') }
)
)
)
)
}
/**
* Given an array of touples [custom id,document] will iterate through
* and place each into the given collection in the database with the
* custom id is the 'ref' field for the document.
*
* @param {string} collection name of the collection to put the docs into
* @param {Array} docs the documents to put in the database collection
* @return {Array} an array of the documents put in the database
*/
createWithCustomID(collection, touples) {
return this.client.query(
this.q.Map(
touples,
this.q.Lambda(
['id', 'data'],
this.q.Create(
this.q.Ref(this.q.Collection(collection), this.q.Var('id')),
{ data: this.q.Var('data') }
)
)
)
)
}
/**
* Retrieve a document given its ref and collection
*
* @param {string} collection the name of the collection
* @param {string} ref the ID or ref of the document
* @return {Object} the document identified by the query
*/
get(collection, ref) {
return this.client.query(
this.q.Get(
this.q.Ref(
this.q.Collection(collection),
ref
)
)
)
}
/**
* Retrieve the first document that matches the given value
* of a term used to create the index. For example, if we
* have an index called "posts_by_title" whose term was set
* to "title", we can search that index using a value of
* "My Blog Post" to see if any posts' titles match our value.
*
* @param {string} index name of index to search on
* @param {multiple} value the value to match on the index term
* @return {Object} the first matching document
*/
getMatch(index, value) {
return this.client.query(
this.q.Get(
this.q.Match(
this.q.Index(index),
value
)
)
)
}
/**
* Given an index 'all_<items>' with no set terms or values,
* this will return the refs of all documents in that index.
*
* @param {string} index name of the index to use
* @param {integer} size number of docs to be returned per page
* @return {Array} an array of the refs to the docs within
* the index
*/
getAllRefsByIndex(index, size) {
return this.client.query(
this.q.Paginate(
this.q.Match(
this.q.Index(index)
),
{ size: size || this.size }
)
)
}
_buildRef(options) {
return this.q.Ref(this.q.Collection(options.collection), options.ref)
}
/**
* Provided with an index, returns all matching documents
*
* @param {string} index name of the index
* @param {Object} options options that may be passed in include:
* before - ref to document for traversing pagination backward
* after - ref to document for traversing pagination forward
* term - a such term to use with a searchable index
* size - the number of docs to return per page
* scope - the database ref within which to perform the match
* @return {Object} Returns a collection of docs matching
* the query conditions
*/
getAllDocsByIndex(index, options = {}) {
if (options.before && options.before.collection) {
options.before = this._buildRef(options.before)
}
else if (options.after && options.after.collection) {
options.after = this._buildRef(options.after)
}
return this.client.query(
this.q.Map(
this.q.Paginate(
this.q.Match(
this.q.Index(index, options.scope),
options.term
),
{
size: options.size || this.size,
before: options.before,
after: options.after
}
),
ref => this.q.Get(ref)
)
)
}
/**
* Given the ref and collection this will update the
* data of that document.
*
* @param {string} collection the name of the collection
* @param {string} ref the ID or ref of the doc
* @param {Object} data the data to be updated
* @return {Object} the updated document
*/
update(collection, ref, data) {
return this.client.query(
this.q.Update(
this.q.Ref(
this.q.Collection(collection),
ref
),
{ data : data }
)
)
}
/**
* Given the ref and collection this will replace the
* data of that document whose fields match the given data.
* Any old fields in the document that are not mentioned in
* the data param are removed.
*
* @param {string} collection the name of the collection
* @param {string} ref the ID or ref of the doc
* @param {Object} data the data to be replace
* @return {Object} the updated document
*/
replace(collection, ref, data) {
return this.client.query(
this.q.Replace(
this.q.Ref(
this.q.Collection(collection),
ref
),
{ data: data }
)
)
}
/**
* Destroys a document
*
* @param {string} collection the name of the collection
* @param {string} ref the ID or ref of the doc
* @return {Object} the deleted document
*/
delete(collection, ref) {
return this.client.query(
this.q.Delete(
this.q.Ref(
this.q.Collection(collection),
ref
)
)
)
}
paginateDB(dbName, size) {
return this.client.query(
this.q.Paginate(
this.q.Database(dbName),
{ size: size || this.size }
)
)
}
getDatabase(dbName) {
return this.client.query(
this.q.Get(
this.q.Database(dbName)
)
)
}
}
module.exports = FaunaConnection