Browse Source

resource class and tests

tags/v1.0.0-alpha.0
ojizero 1 year ago
parent
commit
bf448819fb
No account linked to committer's email address
3 changed files with 167 additions and 3 deletions
  1. 122
    1
      src/resource.ts
  2. 44
    1
      test/resource.spec.ts
  3. 1
    1
      tsconfig.json

+ 122
- 1
src/resource.ts View File

@@ -1 +1,122 @@
export default class Resource {}
import { Client } from './client'
import method, { MethodSpec } from './method'

const defaultBaseSpecs: { [k: string]: MethodSpec } = {
list: {
path: '/',
method: 'GET',
},
get: {
path: '/:id',
method: 'GET',
},
edit: {
path: '/:id',
method: 'POST',
},
add: {
path: '/',
method: 'POST',
},
del: {
path: '/:id',
method: 'DELETE',
},
}

export class Resource {
client: Client
baseRoute: string
enabledRoutes: string[]
methodFactory: any

constructor (
client: Client,
baseRoute: string,
enabledRoutes?: string[],
extraMethods?: { [k: string]: any },
) {
this.client = client
this.baseRoute = baseRoute.trim()

if (this.baseRoute.endsWith('/')) this.baseRoute = this.baseRoute.slice(0, -1)

this.enabledRoutes = enabledRoutes || [
'list',
'get',
'edit',
'add',
'del',
]

this.methodFactory = this.generateMethodFactory()

this.initialize()
this.setExtraMethods(extraMethods)
}

initialize () {
this.enabledRoutes.forEach((route) => {
const routeMethod = this.methodFromRoute(route)

Object.defineProperty(this, route, {
value: routeMethod,
writable: false,
enumerable: true, // TODO: is it okay to have them enumerable ?
})

// Add is aliased as set
if (route === 'add') {
Object.defineProperty(this, 'set', {
value: routeMethod,
writable: false,
enumerable: true, // TODO: is it okay to have them enumerable ?
})
}
// Del is aliased as delete
if (route === 'del') {
Object.defineProperty(this, 'delete', {
value: routeMethod,
writable: false,
enumerable: true, // TODO: is it okay to have them enumerable ?
})
}
})
}

methodFromRoute (route: string) {
let spec = defaultBaseSpecs[route]
const prefix = this.baseRoute
const suffix = spec.path

spec = {
...spec,
path: `${prefix}${suffix}`
}

return this.methodFactory(spec)
}

generateMethodFactory () {
return method(this.client)
}

setExtraMethods (extraMethods?: { [k:string]: any }) {
if (!extraMethods) return

Object.entries(extraMethods)
.forEach(([method, fn]) => {
Object.defineProperty(this, method, {
value: fn,
writable: false,
enumerable: true, // TODO: is it okay to have them enumerable ?
})
})
}
}

export default function resrouceGenerator (client: Client) {
return function (baseRoute: string, enabledRoutes?: string[], extraMethods?: { [k:string]: any }): Resource {
return new Resource(client, baseRoute, enabledRoutes, extraMethods)
}
}

+ 44
- 1
test/resource.spec.ts View File

@@ -1,3 +1,46 @@
/// <reference path='typings/globals.d.ts' />

import resourceGenerator from '../src/resource'

describe('Resource', () => {
// TODO:
let client
let resourceFactory
let resource

before (() => {
resourceFactory = resourceGenerator(client)
})

describe('Rsource instantiation', () => {
it('exposes basic CRUD API', () => {
client = { request: sinon.spy() }

resource = resourceFactory('/mock-base')

expect(resource)
.to.include.all.keys('list', 'get', 'edit', 'del')
})

it('can be extended with additional methods', () => {
client = { request: sinon.spy() }

resourceFactory = resourceGenerator(client)

resource = resourceFactory('/mock-base', undefined, { extraMethod: () => {} })

expect(resource)
.to.include.all.keys('list', 'get', 'edit', 'del', 'extraMethod')
})

it('can limit exposed default methods', () => {
client = { request: sinon.spy() }

resourceFactory = resourceGenerator(client)

resource = resourceFactory('/mock-base', ['list', 'get'])

expect(resource)
.to.include.all.keys('list', 'get')
})
})
})

+ 1
- 1
tsconfig.json View File

@@ -4,7 +4,7 @@
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
"lib": [ "es2015" ],
"lib": [ "es2017" ],
"allowJs": false,
"declaration": true,
"declarationMap": true,

Loading…
Cancel
Save