Giter VIP home page Giter VIP logo

resource's Introduction

resource

A resource can be considered a combination of a Model and a Controller. Resource methods can have associated schemas which act as a contract for the input and output of the method. Using resources provides unified invocation and validation of all function arguments and results.

Features

  • Provides EventEmitters for all resource methods
  • Provides hooks ( before, after ) for all resource methods
  • Methods' input and output arguments are validated with mschema
  • Built in datasource persistence using JugglingDB

Install with npm

npm install resource

Install with component

component install bigcompany/resource

API

resource.define(name, controller [optional], mschema [optional] )

Defines a new type of Resource.

name

The name of the new resource to define. Example: weapon

controller

An optional CommonJS module with exported methods. Any functions the CommonJS module exports are interpreted as controller methods.

mschema

An optional mschema to the define the properties and methods of the resource using a schema.

Resource.method(name, fn, mschema [optional])

Maps a new function to the resource.

name

The name of the method as it should appear on the resource. Example: fire

fn

The JavaScript function to bind to the method.

mschema

An optional mschema to the define the input and output of the method.

Resource.property(name, mschema [optional])

Maps a new property to the resource.

name

The name of the property to add to the resource. Example: ammo

mschema

An optional mschema to the define the input and output of the method.

Resource.persist(datasource)

Enables persistence of Resource instances to a datasource.

Adds the following methods to the resource:

  • Resource.all
  • Resource.create
  • Resource.destroy
  • Resource.find
  • Resource.get
  • Resource.update
  • Resource.updateOrCreate

datasource

The type of datasource to use. Can be string such as memory or an object literal such as { type: 'couchdb', username: 'foo', password: 'bar' }

Tests

tap test

resource's People

Contributors

fotoverite avatar jfhbrook avatar luk- avatar marak avatar wolfbiter avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

resource's Issues

Remove JugglingDB / Simplify Persistence Layer

The JugglingDB and jugglingdb-nano modules should be removed.

The extra layer added to resource persistence is cumbersome and not very good.

It would be much better to remove JugglingDB support and only focus on supporting CouchDB for now.

id property is always added to resource schema

It seems that the property id is always added to the resource schema. In some cases this is superfluous.

Remove the id property as a default. Only add id to the schema if the resource is persisted.

Low priority.

schema for return values of resource method

it would be beneficial to have a schema for the return values of a resource method because then we could get free documentation and validation, among probably other things.

resource.use('') fails

info: installing  to /home/kane/projects/bighack/bigspace/resources

fs.js:684
  return binding.stat(pathModule._makeLong(path));
                 ^
Error: ELOOP, too many symbolic links encountered '/home/kane/projects/bighack/resources/node_modules/resources/node_modules/resources/node_modules/resources/node_modules/resources/node_modules/resources/node_modules/resources/node_modules/resources/node_modules/resources/node_modules/resources/node_modules/resources/node_modules/resources/node_modules/resources/node_modules/resources/node_modules/resources/node_modules/resources/node_modules/resources/node_modules/resources/node_modules/resources/node_modules/resources/node_modules/resources/node_modules/.bin/express'
    at fs.statSync (fs.js:684:18)
    at /home/kane/projects/bighack/resource/lib/helper.js:6:16
    at Array.forEach (native)
    at helper.copyDir (/home/kane/projects/bighack/resource/lib/helper.js:5:7)
    at /home/kane/projects/bighack/resource/lib/helper.js:12:7
    at Array.forEach (native)
    at helper.copyDir (/home/kane/projects/bighack/resource/lib/helper.js:5:7)
    at /home/kane/projects/bighack/resource/lib/helper.js:12:7
    at Array.forEach (native)
    at helper.copyDir (/home/kane/projects/bighack/resource/lib/helper.js:5:7)

[jugglingdb] Cradle adapter not leveraging views

The code for a "find" eventually finds its way to this code chunk:

CradleAdapter.prototype.models = function(model, filter, callback, func) {
    this.client.all(
       {include_docs: true},
       errorHandler(callback, function(res, cb) {
          var docs = res.map(function(doc) {
             return idealize(doc); 
          });
          var filtered = filtering(docs, model, filter, this._models)
          func ? func(filtered, cb) : cb(filtered);
       }.bind(this))
    );
};

This is wrong. Instead of pulling down ALL docs then filtering, the filtering function should be implicitly pushed to the couchdb and then used to run these queries on the database instead of locally.

Chaining .use resources

Wouldn't it be nice if we could chain .use calls, all that would require would be to change this line to return this, is that an option? If not how about passing arrays into .use like resource.use(['http', 'socket']);

Should not found be an error?

Right now we if we can't find a document, we call back with an error. However, the error doesn't have too much information in it and user has to match against the message error to find out what happened.

Should we do that? In an ORM-ish/database access layer, not finding the document seems like a pretty normal occurrence, could we just return null as the document?

Aggregate `resource.start` method

resource should have a method resource.start that intelligently aggregates all resource.start methods for all included resources.

considerations:

  • configuration data to be passed into individual .start methods
  • order in which each resource's .start gets called

make resource into a resource

so it has schemas, hooks, etc. #20 solves all of my use cases for wanting resource to be a resource, so that's enough for me, but eventually we could resource-ify all the methods.

Creating new resources changes the schema on the resource

If I run this code:

var resource = require('resource');

var schema = {
    properties: {
        name: {
            description: 'name property',
            type     : 'string',
            required : true,
            minLength: 1
        }
    }
};

var room = resource.define('room', { schema: schema });
room.persist('memory');

console.log('\ncreate resource');
console.log('===============');

console.log('\n> create a invalid room');
room.create({}, function(err, res) {

    console.log('error must be not null: ', err);
    console.log('constraint must be true: ' + room.schema.properties.name.required);

    console.log('\n> create a invalid room');
    room.create({name: ''}, function(err, res) {
        console.log('error must be not null: ', err);
        console.log('constraint must be true: ' + room.schema.properties.name.required);

        console.log('\n> create a valid room');
        room.create({name: 'my room'}, function(err, res) {

            console.log('error must be null: ', err);
            console.log('constraint must be true: ' + room.schema.properties.name.required);

            console.log('\n> create a invalid room');
            room.create({}, function(err, res) {
                console.log('error must be not null: ', err);
                console.log('constraint must be true: ' + room.schema.properties.name.required);
            });
        });
    });
});


I get the following output:


create resource
===============

> create a invalid room
error must be not null:  [Error: Validation error: [
  {
    "property": "name",
    "constraint": "required",
    "expected": true,
    "actual": false,
    "message": "Required value is missing"
  }
]]
constraint must be true: true

> create a invalid room
error must be not null:  [Error: Validation error: [
  {
    "property": "name",
    "constraint": "required",
    "expected": true,
    "actual": false,
    "value": "",
    "message": "Required value is missing"
  }
]]
constraint must be true: true

> create a valid room
error must be null:  null
constraint must be true: false

> create a invalid room
error must be not null:  null
constraint must be true: false

Seems like the parsing of the schema in mschema module does modify the schema itself. Take a look at the index.js inside the mschema module at line 98.

So after a valid room instance is created the schema changes of the room resource and all the following calls to create a invalid resource do not validate the model properly. Am I missing something?

I used the resource v 0.5.2

Add `Resource.init` method detection

When using a resource check to see if the resource has a resource.init method. If this method is available on the resource then execute it immediately.

The Resource.init method will be used to indicate the resource requires some asynchronous operation before it can be Resource.start.

In Resource.start it's expected that something will happen ( like starting a service ).
In Resource.init it's expected that nothing outside of initializing the resource will happen.

how and where to look for resources

this is something that needs to be finalized, implemented, and tested, so here's what i am thinking so far.

install (async):

  • if in appDir + '/resources'/, npm install to appDir + '/node_modules/'
  • if not in appDir + '/node_modules/', npm install resource package from npm registry
  • install any dependencies that are not already installed to appDir + '/node_modules/' + resource.path

use (async):

  • install and load

load (sync):

  • require resource from appDir + '/node_modules/'

Resource copying can be confusing for resource developers

When a resource is .use() in an application, it will always check the resources package for the existence of that resource. If that resource is found in resources, a copy of it will be made into the current applications directory + /resources.

This is really useful for developers building applications with resources, but it can be slightly confusing to the work-flow of developers who are building new resources.

The issue arises in that sometimes you don't want a copy of the resource made, like when you are inside the require.resolve('resources') and are making change to a resource / building a new resource.

A possible solution would be setting this as an option in on the resource singleton itself, or detecting if we are inside require.resolve('resources') and not using the cache.

support for nested resources

a resource should be able to contain a resource instance within any of its properties. this is currently possible with using ids as a placeholder for child instances, but then it takes multiple requests to create or get the entire root instance.

[persistence] Persistence engine with couchdb has problems when documents are processed outside the engine

Basically, if you modify any documents using futon, you're going to have a bad time.

Here's tests:

5e7e4f9

tl;dr: updateOrCreate a creature, modify the creature using mikeal/request, get the creature, modify it with the persistence engine, and update it.

Here's the output from that test (tl;dr: modifications to life do not register after get, and returned object after get does not conform to update's schema):

# modify persisted documents outside of jugglingdb
ok 68 successfully created korben
ok 69 korben has life 10
ok 70 successfully requested couchdb document
ok 71 successfully modified couchd document
ok 72 successfully got korben
not ok 73 korben has life 100
  ---
    file:   /home/josh/dev/bigcompany/resource/index.js
    line:   733
    column: 9
    stack:  
      - getCaller (/home/josh/dev/bigcompany/resource/node_modules/tap/lib/tap-assert.js:418:17)
      - assert (/home/josh/dev/bigcompany/resource/node_modules/tap/lib/tap-assert.js:21:16)
      - Function.equal (/home/josh/dev/bigcompany/resource/node_modules/tap/lib/tap-assert.js:162:10)
      - Test._testAssert [as equal] (/home/josh/dev/bigcompany/resource/node_modules/tap/lib/tap-test.js:86:16)
      - /home/josh/dev/bigcompany/resource/test/persistence.js:291:13
      - /home/josh/dev/bigcompany/resource/index.js:685:29
      - afterHooks (/home/josh/dev/bigcompany/resource/index.js:733:9)
      - callbackWrap (/home/josh/dev/bigcompany/resource/index.js:681:18)
      - _args (/home/josh/dev/bigcompany/resource/index.js:651:33)
      - exports.enable.r.method.description (/home/josh/dev/bigcompany/resource/lib/persistence.js:140:7)
    found:  10
    wanted: 100
  ...
not ok 74 successfully updated korben
  ---
    type:    Error
    message: |
      Invalid arguments for method `creature.update`. [
        {
          "attribute": "type",
          "property": "metadata",
          "expected": "object",
          "actual": "object",
          "message": "must be of object type"
        },
        {
          "attribute": "type",
          "property": "items",
          "expected": "array",
          "actual": "object",
          "message": "must be of array type"
        }
      ]
    code:    ~
    errno:   ~
    file:    /home/josh/dev/bigcompany/resource/index.js
    line:    535
    column:  29
    stack:   
      - {
      - "attribute": "type",
      - "property": "metadata",
      - "expected": "object",
      - "actual": "object",
      - "message": "must be of object type"
      - },
      - {
      - "attribute": "type",
      - "property": "items",
      - "expected": "array",
      - "actual": "object",
      - "message": "must be of array type"
      - }
      - ]
      - execute (/home/josh/dev/bigcompany/resource/index.js:535:29)
      - /home/josh/dev/bigcompany/resource/index.js:409:16
      - beforeHooks (/home/josh/dev/bigcompany/resource/index.js:471:16)
      - /home/josh/dev/bigcompany/resource/index.js:400:14
      - beforeAllHooks (/home/josh/dev/bigcompany/resource/index.js:440:16)
      - EventEmitter.fn [as update] (/home/josh/dev/bigcompany/resource/index.js:391:12)
      - /home/josh/dev/bigcompany/resource/test/persistence.js:295:20
      - /home/josh/dev/bigcompany/resource/index.js:685:29
      - afterHooks (/home/josh/dev/bigcompany/resource/index.js:733:9)
      - callbackWrap (/home/josh/dev/bigcompany/resource/index.js:681:18)
  ...
not ok 75 korben has life 50
  ---
    file:   /home/josh/dev/bigcompany/resource/index.js
    line:   547
    column: 20
    stack:  
      - getCaller (/home/josh/dev/bigcompany/resource/node_modules/tap/lib/tap-assert.js:418:17)
      - assert (/home/josh/dev/bigcompany/resource/node_modules/tap/lib/tap-assert.js:21:16)
      - Function.equal (/home/josh/dev/bigcompany/resource/node_modules/tap/lib/tap-assert.js:162:10)
      - Test._testAssert [as equal] (/home/josh/dev/bigcompany/resource/node_modules/tap/lib/tap-test.js:86:16)
      - /home/josh/dev/bigcompany/resource/test/persistence.js:299:15
      - execute (/home/josh/dev/bigcompany/resource/index.js:547:20)
      - /home/josh/dev/bigcompany/resource/index.js:409:16
      - beforeHooks (/home/josh/dev/bigcompany/resource/index.js:471:16)
      - /home/josh/dev/bigcompany/resource/index.js:400:14
      - beforeAllHooks (/home/josh/dev/bigcompany/resource/index.js:440:16)
    found:  ~
    wanted: 50
    type:   
      found:  undefined
      wanted: undefined
  ...

I suspect that once the schema issues are resolved, that couchdb will fail to update due to an update conflict because jugglingdb appears to be caching.

resource.resources should be object containing subresources of resource

this way resource stores all the resources in the same format as other resources (such as auth, socket, persistence, github, template, etc) can store subresources. this way we can implement docs, package, etc to iterate through subresources.

the proposed name of a subresource is parent-child as in auth-github. (or does auth::github make more sense?) the proposed way to access a subresource is parent.child as in auth.github, which should be reflected when generating documentation.

.DS_Store issues with fs datasource

There seems to be some issues with resource.all while using the fs datasource and a .DS_Store file is encountered.

This will cause an error in the resource.all call looking for a .DS_Store.json file which doesn't exist.

This issue may also apply to other files that may errantly exist in the /db/ folders.

Lazy dependency loading breaks with synchronous methods

To reproduce, create a big project like the following:

josh@onix:/tmp/big-test$ ls -R
.:
node_modules  test.js  view

./node_modules:
big  resource  resources

./view:
josh@onix:/tmp/big-test$ cat test.js
var big = require('big');

var view = big.use('view');

var _view = view.create({ path: process.cwd() + '/view' });

_view.load();
josh@onix:/tmp/big-test$ 

When you run this, big tries to lazily install cheerio as a dependency for the view resource on view.create, but because the method is synchronous _view ends up being undefined and the call to load fails:

josh@onix:/tmp/big-test$ node test.js
info: installing view to /tmp/big-test/resources/view
warn: view resource is missing a required dependency: cheerio
warn: spawning npm to install missing dependencies
exec: npm install [email protected]
warn: deffering execution of `view.create` since dependencies are missing

/tmp/big-test/test.js:7
_view.load();
      ^
TypeError: Cannot call method 'load' of undefined
    at Object.<anonymous> (/tmp/big-test/test.js:7:7)
    at Module._compile (module.js:449:26)
    at Object.Module._extensions..js (module.js:467:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.runMain (module.js:492:10)
    at process.startup.processNextTick.process._tickCallback (node.js:244:9)

If you install cheerio before running this, it works just fine because the dependency is already installed and view.create is able to execute properly.

Move persistence code into separate resource

The persistence code should be kept in a separate resource.

Ideally, every different type of datasource would be a separate resource ( couch, redis, etc ) acting as an adapter to the persistence resource.

This would allow us to remove JugglingDB vendor from resource core, and put it into the persistence resource instead.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.