npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

objectstore

v0.0.5

Published

Object-relation database

Downloads

3

Readme

Objectstore

Version: 0.0.3 Basic Functionality

Build Status

Objectstore is a database for storing Objects that can be related to each other.

It is designed to be a low-friction backing store for web apps that need to implement structure and access control on collections of objects.

You use Object store to hold all items (users, groups, documents, whatever) your app needs.

Each item has a JSON blob for it's data.

You create relationships to structure connections between items, e.g. join users in to a group, collect documents in to a folder.

Use Objectstore either as a library in your own app, or run it as a REST server. Methods are exposed to allow you to control the server programatically, and a script is provided to get it running it out of the box.

Objectstore uses Postgresql as it's backend.

Concept

Objectstore has Objects and Relationships.

The schema looks something like this:

obj (
  id uuid,
  type varchar(16),
  slug varchar(64),
  attrs json
);

rel (
  id uuid,
  rel_id uuid,
  type default null,
  role varchar(8)
);

Objects have an unique uuid id and an arbitrary type, both assigned when created. The slug is optional.

An object's data (attrs) is a JSON blob. Probably best to keep this as a simple key-value object.

id and type are immutable. Slugs can be changed.

You can add an object and set it's attrs. It's expected that attrs will be completely overwritten each time, not have their individual fields updated. Fetch an object, change some attrs, write the whole thing back.

You can create a relationship (rel) between two object, with an optional role, expiration and position.

You use relationships, types and roles to associate objects with each other..

These relationships are the main reason Objectstore exists.

Some example uses are:

  • A collection of objects in a container
  • user/group membership with expiration
  • users with roles in a group
  • user role in group controlling access to items in a collection

Use slugs to find named objects without using their id (e.g. looking up a user by username, looking up an item in a collection based on a url fragment)

Quickstart

Node Module

npm install objectstore

See config/index.sample.js for an example of how the config object should look.

var os = require('objectstore').api(config);
os.add({type:'doc'}, next);

Simple server

npm install objectstore
grunt reset
var server = require('objectstore').server(config);
server.start(next);

Standalone Server

Create database

sudo su - postgres
createuser -P os

createdb -O os os_dev
psql -c psql -d os_dev -c 'CREATE EXTENSION "uuid-ossp";'

createdb -O os os_test
psql -c psql -d os_test -c 'CREATE EXTENSION "uuid-ossp";'

createdb -O os os_live
psql -c psql -d os_live -c 'CREATE EXTENSION "uuid-ossp";'

Clone the repo

git clone [email protected]:simonswain/objectstore.git
cd objectstore
npm install
cp config/index.sample.js config/index.js

# set database credentials
emacs config/index.js

# initialise the database
grunt reset
node server

info: Objectstore running on localhost:8002

API

All methods take a callback that is called with err and result. The signatures below use next to identify the callback.

Retrieve a set of objects, based on their types and relationships.

find(opts, next)

Find can traverse a list of types (provide them colon separated), using relationships to find a list of objects related by a join object

type type of objects to find

can be <type>, <type:rel_type>, <rel_type:type:rel_type>, and reverses of those.

supply a type - find all of that type

e.g. user // all users doc // all docs group // all groups

supply a type and id - find all of that type related to id (with optional role)

eg users in a group

supply a type and rel_id - find all of that type reversed related to rel_id (with optional role)

eg owner of a doc

doc:image // all images in a doc (id to rel_id -- parent-child) group:user // all users in a group (id to rel_id -- multiparent-child) !user:group // groups a user is in (rel_id to id -- parents by type)

user:group:doc // all docs a user can access (because the docs have been shared to the group by a rel)

!doc:group:user // all users that can access a doc (by the doc's relationship to the group, and user's relationship to the group)

id id of the leftmost object in the type list. The right most objects will be the ones found.

Find is limited to a maximum of 100 returned items. Use base and limit to page through the entire found set,

base and limit parameters can be used in conjunction with #count to effect paging.

The objects in the returned list of items will have a roles field added to them, containing an array of roles that were found between the first and second items objects in the type list. This is equivalent to a user's role in a group.

You could reverse the types to find users whos can access a specific doc

e.g. !doc:group:user.

The ! indicates this is reverse, and the roles will be taken from the middle and last objects.

Find can also be used to find parent-child relationships and their roles, by specifying two types in the list.

e.g folder:doc and !doc:folder

Returns number of objects found using same query parameters as find.

var obj = {
  slug: 'my-slug',
  attrs: {}
}

There is no enforcement of unique slugs. You should check a slug is available before using it. Typically you will use a slug in conjunction with a parent-child relationship, to allow you to find an object by name instead of id.

add(obj, next)
add(obj, rel, next)
add(obj, rels, next)

Callback returns the new object in it's result. The id field will be added

Normally used to set the attrs of an object. Can also be used to change the slug of an object.

set(id, attrs, next)

set(id, 'slug', '<new-slug-value>', next)

Creates a relationship between two objects

rel(id, rel_id [, opts], next)

opts and all it's parameters are optional

{
  role: 'some-role',
  position: <integer>,
  expires: <date>
}

Retrieve single child of id by it's id child_idm ensuring it is of type.

child(id, child_id type, next)

Retrieve related (rel_id) objects of a given node by their type

children(id, type, next)

Retrieve parent (id) objects of a given node by the parent type

parent(id, type, next)

Retrieve a single object

Get an object by id

get(id, next)

Get an object by id, ensuring it's a specific type

get(id, type, next)

Get an object by type, slug and parent.

get(opts, next)

opts are like:

{
  id: '', // id of parent in relationship
  type: '', // type of object to look for
  slug: '' // slug to look for
}

If there is more than one object that matches (e.g. by slug) one will be returned at random, so you probably don't want to use this method if that is possible. You'll need to ensure you're creating unique entries.

Can user object role_id perform action role on doc object rel_id given membership of group object_id.

Can has the same semantics as find when with role_id, but is used to check for permissions on a singly object.

role is optional.

can (role_id, rel_id, id, role, next)

Callback returns true or false

Rest API

GET /

{"objectstore":"0.0.1"}
GET /stats

{"objects":"0","relations":"0"}
POST /reset

HTTP/1.1 200 OK

Create an Object

POST /objects
{"type": "doc"}


HTTP/1.1 200 OK
curl -i -X POST -H "Content-type: application/json" localhost:8002/objects -d '{"type": "doc"}'
HTTP/1.1 200 OK

{"type":"doc","id":"1eeaba49-4a74-4ea6-a98a-a6411fabe7ac"}

Find Objects

GET /objects?type=some-type ...

HTTP/1.1 200 OK

Returns count of number matching the query, and array containing a page of objects.

The query parameters are the same as the javascript api method.

curl -i -X GET -H "Content-type: application/json" localhost:8002/objects?type=doc
HTTP/1.1 200 OK

{
 count: 1,
 objects: [{"type":"doc","id":"1eeaba49-4a74-4ea6-a98a-a6411fabe7ac"}]
}

Default page is 100 objects starting at object zero. Use base and limit to get different pages.

Get an Object

GET /objects?type=some-type ...

Returns count of number matching the query, and array containing a page of objects.

The query parameters are the same as the javascript api method.

curl -i -X GET -H "Content-type: application/json" localhost:8002/objects/1eeaba49-4a74-4ea6-a98a-a6411fabe7ac
HTTP/1.1 200 OK

{"type":"doc","id":"1eeaba49-4a74-4ea6-a98a-a6411fabe7ac"}

Some usage examples

Users and groups

  • create a user
  • create a group
  • add user to group
  • give user role in group
  • find all users with role
  • create a folder and give group a role
  • add a file to folder
  • find which groups can access file based on it's folder
  • find if a user can access a file, and with what role

Release History

  • 07/09/2014 0.0.0 Pre-alpha
  • 07/10/2014 0.0.1 Initial release
  • 27/10/2014 0.0.3 API Changes

License

Copyright (c) 2014 Simon Swain

Licensed under the MIT license.