Skip to content

Instantly share code, notes, and snippets.

@dimik
Created March 7, 2016 08:23
Show Gist options
  • Save dimik/bb656be267f91c1e9c63 to your computer and use it in GitHub Desktop.
Save dimik/bb656be267f91c1e9c63 to your computer and use it in GitHub Desktop.
Traverson context cache decorators and example
import client from './client'
import {Base as TraversonBase} from 'ydw-ui-common/traverson'
TraversonBase.client = client
class CoachApi extends TraversonBase {
getPlanEvents(params) {
return this.getResource([
'planEvents',
'search',
{type: 'link-rel', value: 'by-parameters', params: params}
]).then(data => {
return data._embedded.planEvents
}).catch(() => {
return []
})
}
createMotion(data) {
return this.createResource(
['motions'],
data
)
}
patchPlanEvent(eventId, data) {
return this.patchResource([
'planEvents',
'search',
{type: 'link-rel', value: 'by-event-id', params: {eventId: eventId}},
'self'
], data).catch(() => {
return {}
})
}
deletePlanEvent(eventId) {
return this.deleteResource([
'planEvents',
'search',
{type: 'link-rel', value: 'by-event-id', params: {eventId: eventId}},
'self'
]).catch(() => {
return {}
})
}
}
import traverson from 'traverson'
import JsonHalAdapter from 'traverson-hal'
traverson.registerMediaType(JsonHalAdapter.mediaType, JsonHalAdapter)
const API_CONFIG = {
url: 'http://localhost:8080/api/v1/',
auth: {
user: 'member',
pass: 'member'
}
}
const client = traverson
.from(API_CONFIG.url)
.jsonHal()
.withRequestOptions({
auth: API_CONFIG.auth,
headers: {
'Content-Type': 'application/hal+json',
'Accept': 'application/hal+json',
}
})
export default client
function noop() {}
function promisify(target, name, descriptor) {
let fn = descriptor.value
descriptor.value = function(...args) {
let callback = args[fn.length - 1] || noop
return new Promise(function(resolve, reject) {
fn.apply(target, args.slice(0, fn.length - 1).concat(function(err, val, ...other) {
callback(err, val, ...other)
if (err) {
reject(err)
}
else {
resolve(val)
}
}))
})
}
return descriptor
}
export default promisify
import {promisify} from '../core-decorators'
import ContextCache from './TraversonContextCache'
class TraversonBase {
@ContextCache.store
@ContextCache.retrieve
@promisify
getResource(links, context=TraversonBase.client, callback) {
let [{
params,
...link,
}] = links
if (typeof context.continue === 'function') {
context = context.continue()
}
context = context
.newRequest()
.follow(link.value ? [link] : links)
if (params) {
context = context.withTemplateParameters(params)
}
context.getResource(callback)
}
@promisify
createResource(links, resource, callback) {
if (links.length === 1) {
return this._createResource(links, resource, TraversonBase.client, callback)
}
let getLinks = links.slice(0, -1)
this.getResource(getLinks)
.then(_ => {
this._createResource(
links.slice(-1),
resource,
ContextCache.get(getLinks).continue(),
callback
)
})
}
_createResource(links, resource, context, callback) {
context
.newRequest()
.follow(links)
.convertResponseToObject()
.post(resource, callback)
}
@promisify
patchResource(links, body, callback) {
if (links.length === 1) {
return this._patchResource(links, body, TraversonBase.client, callback)
}
let getLinks = links.slice(0, -1)
this.getResource(getLinks)
.then(_ => {
this._patchResource(
links.slice(-1),
body,
ContextCache.get(getLinks).continue(),
callback
)
})
}
_patchResource(links, body, context, callback) {
context
.newRequest()
.follow(links)
.convertResponseToObject()
.patch(body, callback)
}
@promisify
deleteResource(links, callback) {
if (links.length === 1) {
return this._deleteResource(links, TraversonBase.client, callback)
}
let getLinks = links.slice(0, -1)
this.getResource(getLinks)
.then(_ => {
this._deleteResource(
links.slice(-1),
ContextCache.get(getLinks).continue(),
callback
)
})
}
_deleteResource(links, context, callback) {
context
.newRequest()
.follow(links)
.delete(callback)
}
}
export default TraversonBase
let cache = {}
function putKey(key, val) {
return cache[JSON.stringify(key)] = val
}
function get(key) {
return cache[JSON.stringify(key)]
}
function dropKey(key) {
delete cache[JSON.stringify(key)]
}
function hasKey(key) {
return JSON.stringify(key) in cache
}
function drop() {
cache = {}
}
function retrieve(target, name, descriptor) {
let fn = descriptor.value
descriptor.value = function(links, _, callback) {
return fn.call(target, links.slice(-1), get(links.slice(0, -1)), callback)
}
return descriptor
}
function store(target, name, descriptor) {
let fn = descriptor.value
descriptor.value = function(links, _) {
if (hasKey(links)) {
dropKey(links)
}
let promises = []
for (let i = 0, len = links.length; i < len; i++) {
let key = links.slice(0, i + 1)
if (!hasKey(key)) {
promises.push(
fn.bind(target, key, _, function(err, resource, context) {
putKey(key, context)
})
)
}
}
return promises.reduce(function(soFar, fn) {
return soFar.then(fn)
}, Promise.resolve())
}
return descriptor
}
export default {
store: store,
retrieve: retrieve,
get: get,
hasKey: hasKey,
dropKey: dropKey,
drop: drop,
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment