Share your code. npm Orgs help your team discover, share, and reuse code. Create a free org »

weaver-sdk

8.5.0 • Public • Published

weaver


NPM version NPM downloads Code coverage Build status Dependencies

NPM info

Weaver SDK for JavaScript

A library that gives you access to the Weaver platform from your JavaScript app.


Getting started


Weaver

Installation:

npm i -S weaver-sdk

Create the instance

Weaver = require('weaver-sdk')
weaver = new Weaver()

Be sure to only create a single Weaver instance. If you need to get a reference to a previously instantiated Weaver instance later, or within devtools, just do:

weaver = Weaver.getInstance()

Connect to a running weaver-server

weaver.connect('http://my-weaver-server-url.com')
.then(->
  ...

Sign in with an existing user account for your weaver-server (or admin : admin if you've just cloned a weaver-server and there are no accounts yet)

weaver.signInWithUsername('admin','admin')
.then(->
  ...

Select or create a new Project

# select an existing project 
Weaver.Project.list().then((projects)->
  weaver.useProject(projects[0])
)
 
# .. or create 
= new Weaver.Project(projectNameprojectId)
p.create() # Required. Spins up a new database on weaver-server, which will forevermore be linked with this Weaver.Project 
.then(->
  weaver.useProject(p)
  ...

You have now:

  • Instantiated weaver
  • Connected to a running server
  • Signed-in with a valid user account
  • Selected a project to work on

You're ready to start creating and interacting with nodes.

Nodes

# creates a node (only client side for now) 
= new Weaver.Node('hello-weaver')
n.id()
# -> 'hello-weaver' 
# set a name attribute 
n.set('name''The First Node')
...
n.get('name')
# -> 'The First Node' 
# create a relation 
= new Weaver.Node('how-are-you-weaver')
o.set('name''The Second Node')
n.relation('hasDescendant').add(o)
# getting relations 
n.relation('hasDescendant')
# this returns a Weaver.RelationNode, which has a bunch of properties, among them a 'nodes' array, which contains all the nodes which are linked from the node 'n' via the relation 'hasDescendant' 
 
n.relation('hasDescendant').first()
# -> returns the first relation for this relation key, in this case, the Weaver.Node object referenced by o 
 
# gets the name attribute of the first relation from 'n' for the relation key 'hasDescendant' 
n.relation('hasDescendant').first().get('name')
# -> 'The Second Node' 
# saving to db 
n.save()
.then(->
  ...
# this collects all the pending writes on the node n, and pushes them to the database. 

In our example, calling n.save() will execute several write operations on the database:

  • a create node operation for node n
  • a create attribute operation for the name attribute we set for n
  • a create relation operation for node n to node o, using the relation key hasDescendant

In addition, Weaver.Node.prototype.save is downwards recursive, so it will collect and execute all pending writes on all relations of n, and all relations of those nodes, etc. So, calling n.save() in our example above, will also collect and execute the pending write operations on node o:

  • a create node operation for node o
  • a create attribute operation for the name attribute we set for o

, as o is a relation of n. Pretty sweet, right?

# loading saved nodes from the database 
Weaver.Node.load('hello-weaver')
.then((node)->
  node.get('name')
)
# -> 'The First Node' 
  # nodes are loaded with a depth/eagerness of 1 
  # relations will therefore need to be loaded explicitly 
  Weaver.Node.load('hello-weaver')
  .then((node)->
    node.relation('hasDescendant').first().get('name')
    # -> undefined 
 
    node.relation('hasDescendant').first().load()
 
  ).then((o)->
    o.get('name')
    # -> 'The Second Node' 
  )
 

Reference API

Weaver

Class Methods

  Weaver.getInstance()
  # return the weaver instance 
  Weaver.useModel(model)
  # set's the Weaver.Model to be used by default 
  Weaver.currentModel()
  # returns the current default model 
  Weaver.shout(message)
  # Shout a message to other connected clients 
  Weaver.sniff(callback)
  # Listen to shouted messages and perform the supplied callback 
  Weaver.subscribe(operationTypecallback)
  # Listen perform the supplied callback when events of the provided type are published to the server 
  subscription = Weaver.subscribe('node.created'(msg, node) ->
    if node.id() is 'hello-world'
      console.log 'hello-weaver'
  )
 
  new Weaver.Node('hello-world')
 
  # -> 'hello-weaver' 
  Weaver.unsubscribe(subscription)
  # Unsubscribe from a specific subscription 
  Weaver.clearAllSubscriptions()
  # Unsubscribe from all subscriptions 

Instance methods

  Weaver.prototype.version()
  # returns sdk version 
  Weaver.prototype.serverVersion().then(console.log)
  # logs version of connected server 
  Weaver.prototype.connect(endpoint)
  # sets endpoint of weaver-server to connect to 
  Weaver.prototype.disconnect()
  # breaks connection with weaver-server, if connected to one 
  Weaver.prototype.useProject(project)
  # sets current project to read from/write to 
  Weaver.prototype.currentProject()
  # returns the current project 
  Weaver.prototype.signOut()
  # signs out the current user 
  Weaver.prototype.currentUser()
  # returns the currently signed-in user 
  Weaver.prototype.signInWithUsername(usernamepassword)
  # retrieves a user token, and a user object. 
  Weaver.prototype.signInWithToken(authToken)
  # signs in a user using a token retrieved from the server 
  Weaver.prototype.wipe
  # wipes: 
  #   - all projects on the server 
  #   - all user data on the server 

Weaver.Node


Class methods

  new Weaver.Node(nodeIdgraph)
  # creates a new Weaver.Node, don't forget to call `save` to persist to db 
  Weaver.Node.load(nodeId)
  # returns a Promise which will resolve the specified node if it exists 
  Weaver.Node.get(nodeId)
  # creates a shallow Node with the specified id 
  # note: does not create a create.node operation in pendingWrites, so node.save() will not push a node creation operation to the server. 
  # not recommended unless you know what you're doing, use Weaver.Node.load instead 
  Weaver.Node.firstOrCreate(nodeId)
  # gets the node matching the id if it exists, or constructs a new node with the specified id 
  Weaver.Node.batchSave(array)
  # pass an array of nodes with pendingWrites to save them all at once with a single server transaction 
  Weaver.Node.batchDestroy(array)
  # pass an array of nodes to destroy them all at once with a single server transaction 

Instance methods

  Weaver.Node.prototype.load()
  # same as Weaver.Node.load(Weaver.Node.prototype.id()) 
  Weaver.Node.prototype.id()
  # returns the id of a node 
  Weaver.Node.prototype.attributes()
  # returns a map of loaded attributes on this node 
  Weaver.Node.prototype.relations()
  # returns a map of loaded relations on this node 
  Weaver.Node.prototype.set(keyvalue)
  # sets an attribute on the node 
  Weaver.Node.prototype.unset(key)
  # unsets an attribute on the node 
  Weaver.Node.prototype.get(key)
  # gets the value for a given attribute key on the node 
  Weaver.Node.prototype.relation(key)
  # returns a Weaver.Relation for the given relation key 
  # note, creates an empty Weaver.Relation object if no loaded relation are found. 
  Weaver.Node.prototype.clone(newIdrelationsToTraverse...)
  # clones a node. 
  # recursively clones relations of the node if relationsToTraverse is defined 
  Weaver.Node.prototype.equals(node)
  # checks if the supplied node refers to the same node as the instance from a database perspective (id comparison) 
  Weaver.Node.prototype.save()
  # executes all pending db writes on the instance 
  # is recursively called on all loaded relations of this node 
  Weaver.Node.prototype.destroy()
  # destroys the instance, also on the db 

Weaver.Relation


Instance methods

  Weaver.Relation.prototype.load()
  # loads all nodes on this relation, so they will no longer be shallow 
  Weaver.Node.prototype.to(node)
  # returns the relationNode linking to the passed node, or throws an error if no relationNode is present linking to the passed node 
  Weaver.Node.prototype.all()
  # returns all nodes linked to with the current relation key 
  Weaver.Node.prototype.first()
  # returns the first node linked to with the current relation key 
  Weaver.Node.prototype.add()
  # links to the passed node from the instance relation 
  Weaver.Node.prototype.remove(node)
  # unlinks the passed node from the relation instance 

Weaver.Project


Class methods

  Weaver.Project.list()
  # Lists all projects on the server that the logged in user has access to. 

Instance Methods

  new Weaver.Project(@name@projectId)
  # creates a new Weaver.Project clientside 
  Weaver.Project.prototype.create()
  # Publishes a create-project operation on the server. 
  # Consider this as the persistent constructor 
  Weaver.Project.prototype.destroy()
  # Self-explanatory. This is a persisting operation. 
  Weaver.Project.prototype.wipe()
  # Wipes all data from this project, without deleting the project itself 
  Weaver.Project.prototype.freeze()
  # Freezes project in it's current state, preventing any further writing 
  Weaver.Project.prototype.unfreeze()
  # Unfreezes project, allowing writing as normal 
  Weaver.Project.prototype.isFrozen()
  # Return's the frozen state of this project 
  Weaver.Project.prototype.rename(name)
  # Renames this project on the server 
  Weaver.Project.prototype.clone()
  # Clone's this project in it's entirety 
  Weaver.Project.prototype.getSnapshot(shouldBeJsonshouldBeZipped)
  # Returns a snapshot of this project, defaults to zipped = false, shouldBeJson = true 
  Weaver.Project.prototype.clone()
  # Clone's this project in it's entirety 
  Weaver.Project.prototype.addApp(appNameappData)
  # Add some meta data to this project relating to a specific app 
  Weaver.Project.prototype.removeApp(appName)
  # Removes some meta data from this project relating to a specific app 
  Weaver.Project.prototype.getApps()
  # Returns a map which contains metadata for each app relating to this project, keyed by the app's name 

Weaver.User


Class Methods

  Weaver.User.get(authToken)
  # create a shallow Weaver.User with aupplied userToken set 
  Weaver.User.list()
  # lists all users on the server 
  Weaver.User.listProjectUsers()
  # lists all users with access to the current project 

Instance Methods

  Weaver.User.prototype.id()
  # Returns the userId for the User instance 
  Weaver.User.prototype.save()
  # Persists user data to server 
  Weaver.User.prototype.changePassword(password)
  # Changes a user's password 
  Weaver.User.prototype.signUp()
  # Saves the user and signs in as currentUser 
  Weaver.User.prototype.destroy()
  # Destroys the user 
  Weaver.User.prototype.getProjectsForUser()
  # Returns the projects a user has access to 

Weaver.Query


Class methods

  Weaver.Query.profile(callback)
  # Fires the callback whenever a query is resolved. 
  # The callback is passed one argument, which contains information about the query which was just resolved 
  Weaver.Query.clearProfilers()
  # Destroys any notifiers which were created 

Instance methods

  Weaver.Query.prototype.find(Constructor)
  # Executes the query and returns results constructed with the supplied Constructor, if one is given 
  Weaver.Query.prototype.count()
  # Executes the query and returns a count of the results 
  Weaver.Query.prototype.first()
  # Executes the query and returns the first result 
  Weaver.Query.prototype.limit(limit)
  # Limits the amount of results (default/maximum permitted is 1,000) 
  Weaver.Query.prototype.skip(skip)
  # Skips the passed amount of results. Useful for Result pagination 
  Weaver.Query.prototype.order(keysascending)
  # Orders results based on their value for a given attribute key 
Exclusion Criteria
  Weaver.Query.prototype.restrict(nodes)
  # Adds a restriction on the query based on the ids of the array of passed nodes. (an array of ids is acceptable here too) 
  Weaver.Query.prototype.equalTo(keyvalue)
  # Restricts based on attributes. Results must match the passed key : value args 
  Weaver.Query.prototype.notEqualTo(keyvalue)
  # Restricts based on attributes. Results must not match the passed key : value args 
  Weaver.Query.prototype.startsWith(keyvalue)
  Weaver.Query.prototype.endsWith(keyvalue)
  # Restricts based on attributes. Results must have a value which matches the passed key, and which value matches the rule described. 
  Weaver.Query.prototype.lessThan(keyvalue)
  Weaver.Query.prototype.greaterThan(keyvalue)
  Weaver.Query.prototype.lessThanOrEqualTo(keyvalue)
  Weaver.Query.prototype.greaterThanOrEqualTo(keyvalue)
  # These all restrict based on attributes. The attribute value must respect the mathematical rule described 
  Weaver.Query.prototype.hasRelationIn(keynode...)
  Weaver.Query.prototype.hasNoRelationIn(keynode...)
  # These restrict based on incoming relations. key is the relation key, and node is the node which the relation must originate from. node is an optional argument here, if node is not passed, then this criteria is considered passed if ANY relation exists for the passed key. 
  Weaver.Query.prototype.hasRelationOut(keynode...)
  Weaver.Query.prototype.hasNoRelationOut(keynode...)
  # Same as above, but for outgoing relations instead 
  Weaver.Query.prototype.
  # 
Extra loading instructions
  Weaver.Query.prototype.selectOut(relationKeys...)
  # Will fully load outgoing relations with a relation key matching any one of the passed arguments 
  Weaver.Query.prototype.selectRecursiveOut(relationKeys...)
  # As above, but will recursively load 
  Weaver.Query.prototype.selectIn(relationKeys...)
  # Will fully load incoming relations with a relation key matching any one of the passed arguments. 
  # The incoming relations become part of the _relationsIn_ member of the 
  # loaded nodes. 
  nodes[0].relationsIn['relationKey'].nodes
  # If multiple relationKeys are specified in the same call, it will follow 
  # path along incoming relations. so a call with ('key1', 'key2') will load 
  # nodes with a 'key1' relation to a query result node, and then nodes with 
  # a 'key2' relation to the additionally loaded nodes. Nodes with a 'key2' 
  # relation to the original result node will not be loaded. 
  # 
  # To load nodes with different relations in to a query result node, use 
  # multiple selectIn calls. 
  Weaver.Query.prototype.select(attributeKeys...)
  # Will restrict the attributes of loaded nodes to those specified 
  Weaver.Query.prototype.selectRelations(relationKeys...)
  # Will restrict the relations of loaded nodes to those specified 
Nesting queries / FOAF

Any query which contains a node as an argument may instead be passed a nested query.

  new Weaver.Query().hasRelationOut('hasChild',
    new Weaver.Query().hasRelationOut('attendsSchool''*')
  )
  # will return all nodes which have an outgoing hasChild relation to a node which has an outgoing attendsSchool relation. 

Weaver.Plugin


Class Methods

  Weaver.Plugin.load(pluginName)
  # Load a Weaver.Plugin which exists on the server 
  Weaver.Plugin.list()
  # lists all plugins on the server 

Instance Methods

  Weaver.Plugin.prototype.printFunctions()
  # Prints the functions available for this plugin 
  Weaver.Plugin.prototype.getPluginName()
  # Returns the plugin name 
  Weaver.Plugin.prototype.getPluginVersion()
  # Returns the plugin version 
  Weaver.Plugin.prototype.getPluginAuthor()
  # Returns the plugin author 
  Weaver.Plugin.prototype.getPluginDescription()
  # Returns the plugin description 


Weaver.Model


Creating

Step 1: Define a model

This will create a new Model with the name 'Man'

manModel = new Weaver.Model("Man")

This adds a new getter to any member of the 'Man' model. from now on, calling something like manMember.get('name'), will return the object of the triple manMember -> hasName -> object.

manModel.structure({
  name:"hasName"
})

The previous example added a getter for an attribute, to add a getter for a relation, you should prefix the predicate with an '@'

 manModel.structure({
   name:"hasName"
   type:"@hasType"
 })

Call .setStatic() on a model to set a static property for the model. Now, all members of the 'Man' model will already have the property latinName set to "Homo sapien" upon instantiation. In addition to this, the following triple will be inserted into any connected db manMember -> hasLatinName -> "Homo sapien".

   manModel.structure({
     name:"hasName"
     type:"@hasType"
     latinName: "hasLatinName"
   })
   .setStatic("latinName", "Homo sapien")

When you've finished describing your model, call buildClass() to get a constructor to initialize new members of that model.

   Man = manModel.buildClass()
   trump = new Man()
Step 2: Instantiate a member

Model members extend Weaver.Node. They can be saved to the database, to be loaded later, and if their constructor is passed an argument, The root node of that member will be initialized with that argument as an id.

    typeModel = new Weaver.Model("Type")
    typeModel.structure({
      name:"hasLabel"
    })
    .save();
    Type = typeModel.buildClass();
    manType = new Type("lib:Man")

Dynamic properties for model members can be set with .setProp(propKey, propVal). Use setProp() both for setting attributes and adding relations, the model will figure out what to do based on the structure you provided earlier.

        manType.setProp("name", "The Type node for all men.")
        .save()
Step 3: Nest models to describe complex structures

Include a model member in the definition for another model.

    manModel.structure({
      name:"hasName"
      type: ["@hasType", typeModel.id()]
      latinName: "hasLatinName"
    })
    .setStatic("latinName", "Homo sapien")
    .setStatic("type", manType)

Now all man model members will be instantiated with a hasType relationship to the manType node (the one with id 'lib:Man', also the root of the manType model member).

You can even chain getters together to return deep properties of a model member.

   typeModel = new Weaver.Model("Type")
   typeModel.structure({
     name:"hasLabel"
   })
   .save();
   Type = typeModel.buildClass();
   manType = new Type("lib:Man")
   manType.setProp("name", "Type node for all men")
 
   manModel.structure({
     name:"hasName"
     type:["@hasType", typeModel.id()]
     latinName: "hasLatinName"
     nameOfType: "type.name"  //use a '.' to seperate path segments
   })
   .setStatic("latinName", "Homo sapien")
   .setStatic("type", manType)
   Man = manModel.buildClass()
 
   trump = new Man()
   trump.setProp("name", "Donald Drumpf")
   trump.get("name")         //returns "Donald Drumpf"
   trump.get("latinName")    //returns "Homo sapien"
   trump.get("type")         //returns WeaverModelMember instance
   trump.get("type.name")    //returns "Type node for all men"
   trump.get("nameOfType")   //returns "Type node for all men"
 
   trump.destroy()           //would that it were so easy..

## Creating your own plugins

Got something special that you wish your weaver-server could do? Build your own Weaver.Plugin to add server-side functionality. Define any functionality you want to offload to the server within a Weaver.Plugin, and then access it using an integrated prebuilt interface within the sdk.

We have built a weaver-service bootstrapper here to get you started, so download that, and bootstrap your new service to get started.

The directory in which you bootstrapped your service will already have generated a README.md, but we'll explain what to do here also for ease of reference.

Let's say we made a cloud-sync service, to sync some data with a separate cloud store. First we'll install the bootstrapper: (and yeoman if you haven't already got it)

$ npm install -g yo
$ npm install -g generator-weaver-service

Then we'll run the bootstrapper:

$ yo weaver-service
# be careful not to use any capital letters in the organization name

Then we'll add some configuration to our local weaver-server instance so that it picks up our new service

# in #{weaver-server-root-folder}/config/default.coffee 
...
 
pluggableServices:
    'cloud-sync-service': 'http://localhost:2525' #or whatever port number you chose during bootstrapping 
 
...

Then, back in /cloud-sync-service

$ npm run prepublish
$ node lib/index.js

Your service should now be up-and-running! Restart your weaver-server and make sure you see some acknowledgement of your new service in the startup logs.

2018-05-31 14:06:49 | INFO | Service plugin cloud-sync-service loaded with 3 Swagger paths parsed

Use a weaver sdk to reference your new service, and start playing!

Weaver.Plugin.load('cloud-sync-service')
.then((cloudSync) ->
  cloudSync.myNewFunctionality()
)

Building locally

$ git clone https://github.com/weaverplatform/weaver-sdk-js.git
$ npm i
$ npm run prepublish

Tests

$ npm test

Keywords

none

install

npm i weaver-sdk

Downloadsweekly downloads

240

version

8.5.0

license

GPL-3.0

last publish

collaborators

  • avatar
  • avatar
  • avatar
  • avatar
  • avatar
  • avatar
  • avatar