Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

FaunaError and some more publisherKey methods.

  • Loading branch information...
commit 3760c48ce670826bdf58ee0607ac14d4bb474462 1 parent 89f5e8a
@robey authored
View
101 src/fauna.coffee
@@ -1,5 +1,6 @@
fauna_client = require("./fauna/fauna_client")
exports.FaunaClient = fauna_client.FaunaClient
+exports.FaunaError = fauna_client.FaunaError
rest = require("./fauna/rest")
exports.Rest = rest.Rest
@@ -24,82 +25,15 @@ util = require 'util'
dump = (x) -> util.inspect(x, false, null, true)
-class FaunaError
- constructor: (obj) ->
- @message = obj.error
- for k, v of obj then @[k] = v
class Fauna
- # username/password is optional -- you may set auth with 'setAuth' or 'setKey'.
- constructor: (@username, @password) ->
- if not @password? then @password = ""
- @schema = new Schema()
-
- debug: (message) -> Rest.debug(message)
-
- protocol: "https"
- hostname: "rest.fauna.org"
- apiVersion: "v1"
-
- addClasses: (classes...) ->
- @schema.addClasses(classes...)
-
- setAuth: (username, password) ->
- @debug "Auth as #{username} / #{password}"
- @username = username
- @password = password
-
+
setKey: (key) ->
@debug "Auth as #{key}"
@username = key
@password = ""
- urlFor: (path) ->
- "#{@protocol}://#{encodeURIComponent(@username)}:#{escape(@password)}@#{@hostname}/#{@apiVersion}/#{path}"
-
- get: (path) ->
- Rest.get(url: @urlFor(path)).then (text) ->
- JSON.parse(text)
-
- put: (path, data) ->
- Rest.put(url: @urlFor(path), data: data).then (text) ->
- if text? then JSON.parse(text) else null
-
- post: (path, data) ->
- Rest.post(url: @urlFor(path), data: data).then (text) ->
- if text? then JSON.parse(text) else null
-
- delete: (path) ->
- Rest.delete(url: @urlFor(path)).then (text) ->
- if text? then JSON.parse(text) else null
-
- # ----- helpers
-
- collapseEvents: (data) ->
- items = []
- for event in data.resource.events.reverse()
- if not event.action? then event.action = "create"
- switch event.action
- when "create"
- ref = data.references[event.resource]
- if ref? then items.unshift ref
- when "delete"
- collection = (x for x in items when x.ref != event.resource)
- else
- # ignore
- before = data.resource.before
- if not before? then before = 0
- after = data.resource.after
- items = items.map (item) =>
- newrefs = {}
- for k, v of item.references
- v = if v instanceof Array then v.map((x) -> data.references[x]) else data.references[v]
- newrefs[k] = v
- item.references = newrefs
- @schema.inflate(item, @)
- { before: before, after: after, items: items }
-
# tell fauna to create classes & event sets for us.
# return: { class, event_sets[] }[]
setupSchemas: ->
@@ -111,34 +45,8 @@ class Fauna
)
- # ----- debugging commands
-
- # auth: publisher email
- # returns: publisher record (not very useful)
- deleteEverything: ->
- @delete("everything")
-
-
# ----- publisher keys
- # auth: publisher email
- getPublisherKeys: ->
- @get("keys/publisher").then (data) =>
- @collapseEvents(data).items
-
- # auth: publisher email
- createPublisherKey: ->
- @post("keys/publisher", {}).then (data) => data.resource
-
- getOrCreatePublisherKey: ->
- @getPublisherKeys().then (keys) =>
- if keys.length > 0 then return keys[0].key
- @createPublisherKey().then (key) => key.key
-
- deletePublisherKey: (ref) ->
- if ref.indexOf("keys/publisher/") == 0 then ref = ref.split("/")[2]
- @delete("keys/publisher/#{ref}")
-
deletePublisherKeys: (refs) ->
if refs.length == 0 then return
ref = refs.shift()
@@ -151,10 +59,6 @@ class Fauna
# ----- client keys
- # auth: publisher email
- getClientKeys: ->
- @get("keys/client").then (data) =>
- @collapseEvents(data).items
# auth: publisher email
createClientKey: ->
@@ -277,4 +181,3 @@ class Fauna
exports.Fauna = Fauna
-exports.FaunaError = FaunaError
View
41 src/fauna/fauna_client.coffee
@@ -17,7 +17,7 @@ dump = (x) -> util.inspect(x, false, null, true)
requireOwner = (f) ->
(x...) ->
if not (@ownerAuthentication.username? and @ownerAuthentication.password?)
- return Q.reject(new Error("Requires authentication as owner"))
+ return Q.reject(new FaunaError(error: "Requires authentication as owner"))
@setAuth @ownerAuthentication.username, @ownerAuthentication.password
f.bind(@)(x...)
@@ -30,6 +30,14 @@ asObject = (f) ->
f.bind(@)(x...).then (data) => @unpack(data)
+class FaunaError
+ constructor: (obj) ->
+ @message = obj.error
+ for k, v of obj then @[k] = v
+
+exports.FaunaError = FaunaError
+
+
class FaunaClient
constructor: ->
# three kinds of authentication: owner, publisher, client, user
@@ -63,17 +71,36 @@ class FaunaClient
@schema.addPrototypes(protos...)
setOwnerAuth: (username, password) ->
+ ###
+ Set the username/password to use for requests that require owner
+ permissions. If these are not set, owner-level requests will fail.
+ ###
@ownerAuthentication.username = username
@ownerAuthentication.password = password
-
+ deleteEverything: requireOwner asObject -> @rest("delete", "everything")
+ # tell fauna to create classes & event sets for us.
+ # return: { class, event_sets[] }[]
+ installSchema: ->
+ Q.all(
+ @schema.foreachClass (name, metadata) =>
+ @createClass(name).then (klass) =>
+ Q.all(for setName in metadata.eventSets then @createEventSet(name, setName)).then (sets) =>
+ { "class": klass, "event_sets": sets }
+ )
class _PublisherKeys
get: requireOwner asEventArray -> @rest("get", "keys/publisher")
create: requireOwner asObject -> @rest("post", "keys/publisher")
getById: requireOwner asObject (id) -> @rest("get", "#{id}")
- delete: requireOwner (id) -> @rest("delete", "#{id}")
+ deleteById: requireOwner (id) -> @rest("delete", "#{id}")
+ deleteAll: ->
+ @publisherKeys.get().then (keys) =>
+ Q.all(keys.map((key) => @publisherKeys.deleteById(key._fauna.id)))
+ getOrCreate: ->
+ @publisherKeys.get().then (keys) =>
+ if keys.length > 0 then keys[0] else @publisherKeys.create()
class _ClientKeys
get: requireOwner asEventArray -> @rest("get", "keys/client")
@@ -91,8 +118,12 @@ class FaunaClient
rest: (method, path, data) ->
options = { url: @urlFor(path) }
if data? then options.body = JSON.stringify(data)
- Rest.op(method, options).then (body) ->
+ Rest.op(method, options)
+ .then (body) ->
if body? then JSON.parse(body) else null
+ .fail (error) =>
+ obj = JSON.parse(error.body)
+ if obj.error? then throw new FaunaError(obj) else throw error
# unpack a response of { resource:{}, references:{} }
unpack: (data) ->
@@ -119,6 +150,7 @@ class FaunaClient
if refid? and references[refid]? then event.resource = references[refid]
@schema.inflate(data.resource)
+exports.FaunaClient = FaunaClient
topoSort = (graph) ->
@@ -143,4 +175,3 @@ topoSort = (graph) ->
rv
-exports.FaunaClient = FaunaClient
View
1  src/fauna/rest.coffee
@@ -6,6 +6,7 @@ util = require 'util'
dump = (x) -> util.inspect(x, false, null, true)
+
class RestError
constructor: (@statusCode, @body) ->
@message = "Server response: #{@statusCode}"
View
33 test/test_fauna_client.coffee
@@ -9,6 +9,15 @@ futureTest = test_util.futureTest
describe "FaunaClient", ->
+ it "can catch errors", futureTest ->
+ f = new fauna.FaunaClient()
+ f.setOwnerAuth("u", "p")
+ r = -> f.publisherKeys.get()
+ handler = (options) -> [ null, 440, JSON.stringify(error: "Saturn has been obliterated.", id: 21.5) ]
+ fauna.Rest.withRequestHandler(handler, r).fail (error) ->
+ error.message.should.eql "Saturn has been obliterated."
+ error.id.should.eql(21.5)
+
it "can unpack", ->
f = new fauna.FaunaClient()
obj = f.unpack(JSON.parse(data1))
@@ -65,11 +74,20 @@ describe "FaunaClient", ->
it "sets owner auth", futureTest ->
f = new fauna.FaunaClient()
f.setOwnerAuth("u", "p")
- r = -> f.publisherKeys.delete("x/y/z")
+ r = -> f.publisherKeys.deleteById("keys/publisher/z")
withSuccessfulRequest({}, r).then ([ resp, requests ]) ->
requests.length.should.eql(1)
requests[0].url.should.match(/u:p@/)
+ it "can delete everything", futureTest ->
+ f = new fauna.FaunaClient()
+ f.setOwnerAuth("u", "p")
+ r = -> f.deleteEverything()
+ withSuccessfulRequest(JSON.parse(data3), r).then ([ resp, requests ]) ->
+ requests.length.should.eql(1)
+ requests[0].url.should.match(/everything/)
+ resp.name.should.eql("Sierra Online")
+
# test data from the fauna documentation for GET keys/publisher
data1 = """
@@ -148,3 +166,16 @@ data2 =
class: "cats"
data: { name: "Simba" }
references: { friend: "spooky" }
+
+data3 = """
+{
+ "resource" : {
+ "ref" : "publisher",
+ "class" : "publisher",
+ "ts" : 1365020937579008,
+ "name" : "Sierra Online",
+ "data" : { },
+ "deleted" : false
+ }
+}
+"""
View
62 test/test_publisher_keys.coffee
@@ -40,15 +40,57 @@ describe "FaunaClient.publisherKeys", ->
requests[0].url.should.match(/keys\/publisher\/30159234443248641/)
resp.key.should.eql "AQAAayWp97AEAQBrJamcsAABlnqXMsjdfw3kJU44o1dpDg"
- it "delete", futureTest ->
+ it "deleteById", futureTest ->
f = new fauna.FaunaClient()
f.setOwnerAuth("u", "p")
- r = -> f.publisherKeys.delete("keys/publisher/30159234443248641")
+ r = -> f.publisherKeys.deleteById("keys/publisher/30159234443248641")
fauna.Rest.withRequestHandler(((options) -> [ null, 204, null ]), r).then ([ resp, requests ]) ->
requests.length.should.eql(1)
requests[0].url.should.match(/keys\/publisher\/30159234443248641/)
(resp?).should.eql(false)
+ it "deleteAll", futureTest ->
+ f = new fauna.FaunaClient()
+ f.setOwnerAuth("u", "p")
+ r = -> f.publisherKeys.deleteAll()
+ handler = (options) ->
+ if options.method == "GET"
+ [ null, 200, data1 ]
+ else
+ [ null, 204, null ]
+ fauna.Rest.withRequestHandler(handler, r).then ([ resp, requests ]) ->
+ requests.length.should.eql(4)
+ requests[0].method.should.eql("GET")
+ requests[1 ... 4].map (request) ->
+ request.method.should.eql("DELETE")
+ requests[1 ... 4].map((r) -> r.url.match(/keys\/publisher\/(\d+)/)[1]).sort().should.eql [
+ "30159233572929537"
+ "30159234443248641"
+ "30159234559639553"
+ ]
+
+ it "getOrCreate", futureTest ->
+ f = new fauna.FaunaClient()
+ f.setOwnerAuth("u", "p")
+ r = -> f.publisherKeys.getOrCreate()
+ handler = (options) ->
+ if options.method == "GET"
+ [ null, 200, data4 ]
+ else
+ [ null, 200, data3 ]
+ fauna.Rest.withRequestHandler(handler, r).then ([ resp, requests ]) ->
+ requests.length.should.eql(2)
+ requests[0].method.should.eql("GET")
+ requests[1].method.should.eql("POST")
+ resp.key.should.eql "AQAAayWp97AEAQBrJamcsAABlnqXMsjdfw3kJU44o1dpDg"
+ .then ->
+ handler = (options) -> [ null, 200, data1 ]
+ fauna.Rest.withRequestHandler(handler, r).then ([ resp, requests ]) ->
+ requests.length.should.eql(1)
+ requests[0].method.should.eql("GET")
+ resp.key.should.eql "AQAAayWp_qAAAQBrJamcsAABzAFAUI2ckXGpAt2VjWsyiA"
+
+
# test data from the fauna documentation for GET keys/publisher
data1 = """
{
@@ -138,3 +180,19 @@ data3 = """
}
}
"""
+
+data4 = """
+{
+ "resource" : {
+ "ref" : "keys/publisher",
+ "class" : "sets",
+ "after" : 9223372036854775,
+ "creates" : 0,
+ "updates" : 0,
+ "deletes" : 0,
+ "events" : [
+ ]
+ },
+ "references": { }
+}
+"""
Please sign in to comment.
Something went wrong with that request. Please try again.