app/assets/javascripts/joosy/core/resource/rest.js.coffee in joosy-0.1.0.RC1 vs app/assets/javascripts/joosy/core/resource/rest.js.coffee in joosy-0.1.0.RC2
- old
+ new
@@ -1,76 +1,199 @@
#= require ./rest_collection
+#
+# Resource with the HTTP REST as the backend
+#
+# Example:
+# class Rocket extends Joosy.Resource.REST
+# @entity 'rocket'
+#
+# r = Rocket.find {speed: 'fast'} # queries /rockets/?speed=fast to get RESTCollection
+# r = Rocket.find 1 # queries /rockets/1 to get Rocket instance
+#
+# class Engine extends Joosy.Resource.REST
+# @entity 'engine'
+# @source ->
+# (rocket) "/rockets/#{rocket 'id'}/engines"
+#
+# e = Engine.at(r).find {oil: true} # queries /rockets/1/engies?oil=true
+#
class Joosy.Resource.REST extends Joosy.Resource.Generic
+ #
+ # Default primary key field 'id'
+ #
__primaryKey: 'id'
+
+
+ #
+ # Default value of resource collection
+ # Will try to seek for EntityNamesCollection
+ # Will fallback to Joosy.Resource.RESTCollection
+ #
+ __collection: ->
+ named = @__entityName.camelize().pluralize() + 'Collection'
+ if window[named] then window[named] else Joosy.Resource.RESTCollection
- @entity: (name) -> @::__entityName = name
- @source: (source) -> @::__source = source
+ #
+ # Sets the field containing primary key
+ #
+ # It has no direct use inside the REST resource itself and can be omited
+ # That's said: REST resource can work without primary at all. It's here
+ # just to improve end-users experience for cases when primary exists.
+ #
+ # @param [String] primary Name of the field
+ #
@primary: (primary) -> @::__primaryKey = primary
- constructor: (description) ->
- if @constructor.__isId(description)
+ #
+ # Should NOT be called directly, use .create() instead
+ #
+ # @param [Integer|String|Object] description ID of entity or full data to store
+ #
+ constructor: (description={}) ->
+ if @constructor.__isId description
@id = description
else
super description
@id = @e[@__primaryKey]
- @entityName: ->
- unless @::hasOwnProperty '__entityName'
- throw new Error "Joosy.Resource.REST does not have entity name"
-
- @::__entityName
-
- # Returns single entity if int/string given
+ #
+ # Queries for REST data and creates resources instances
+ #
+ # Returns single entity if integer or string given
# Returns collection if no value or Object (with parameters) given
- @find: (description, callback, options) ->
- if @__isId(description)
- resource = new @(description)
- resource.fetch callback, options
+ #
+ # If first parameter is a Function it's considered as a result callback
+ # In this case parameters will be considered equal to {}
+ #
+ # Example:
+ # class Rocket extends Joosy.Resource.REST
+ # @entity 'rocket'
+ #
+ # Rocket.find 1
+ # Rocket.find {type: 'nuclear'}, (data) -> data
+ # Rocket.find (data) -> data
+ # Rocket.find 1,
+ # success: (data) -> data)
+ # cache: true
+ #
+ # @param [Integer|String|Object] description ID of entity or full data to store
+ # @param [Function|Object] options AJAX options.
+ # Will be considered as a success callback if function given
+ #
+ # @return [Joosy.Resource.REST|Joosy.Resource.RESTCollection]
+ #
+ @find: (description, options) ->
+ if Object.isFunction options
+ options = {success: options}
+
+ if @__isId description
+ resource = @create description
+ resource.fetch options
resource
else
- if Object.isFunction(description) && !callback
- callback = description
+ if !options? && Object.isFunction description
+ options = {success: description}
description = undefined
- resources = new Joosy.Resource.RESTCollection(@, description)
- resources.fetch callback, options
+ resources = new (@::__collection()) this, description
+ resources.fetch options
resources
- fetch: (callback, options) ->
- @constructor.__ajax 'get', @constructor.__buildSource(extension: @id), options, (e) =>
- @__fillData(e)
- callback?(this)
+ #
+ # Queries the resource url and reloads the data from server
+ #
+ # @param [Function|Object] options AJAX options.
+ # Will be considered as a success callback if function given
+ # @return [Joosy.Resource.REST]
+ #
+ fetch: (options) ->
+ if Object.isFunction options
+ callback = options
+ else
+ callback = options?.success
+ delete options?.success
+ @constructor.__ajax 'get', @constructor.__buildSource(extension: @id), options, (e) =>
+ @__fillData e, false
+ callback? this
+ @trigger 'changed'
this
save: ->
- destroy: (callback, options) ->
+ #
+ # Destroys the resource by DELETE query
+ #
+ # @param [Function|Object] options AJAX options.
+ # Will be considered as a success callback if function given
+ # @return [Joosy.Resource.REST]
+ #
+ destroy: (options) ->
+ if Object.isFunction options
+ callback = options
+ else
+ callback = options?.success
+ delete options?.success
+
@constructor.__ajax 'delete', @constructor.__buildSource(extension: @id), options, (e) =>
- callback?(this)
-
+ callback? this
this
+
+ #
+ # Requests the REST member URL with POST or any method given in options.type
+ #
+ # @param [String] ending Member url (like 'foo' or 'foo/bar')
+ # @param [Function|Object] options AJAX options.
+ # Will be considered as a success callback if function given
+ #
+ request: (ending, options) ->
+ if Object.isFunction options
+ callback = options
+ else
+ callback = options?.success
+ delete options?.success
+
+ if options.method || options.type
+ type = options.method || options.type
+ else
+ type = 'post'
+
+ @constructor.__ajax type, @constructor.__buildSource(extension: "#{@id}/#{ending}"), options, callback
- @__isId: (something) -> Object.isNumber(something) || Object.isString(something)
+ #
+ # Checks if given description can be considered as ID
+ #
+ # @param [Integer|String|Object] something Value to test
+ # @return [Boolean]
+ #
+ @__isId: (something) ->
+ Object.isNumber(something) || Object.isString(something)
+ #
+ # jQuery AJAX wrapper
+ #
+ # @param [String] method HTTP Method (GET/POST/PUT/DELETE)
+ # @param [String] url URL to query
+ # @param [Object] options AJAX options to pass with request
+ # @param [Function] callback XHR callback
+ #
@__ajax: (method, url, options={}, callback) ->
- $.ajax url, Object.extended(
+ $.ajax url, Joosy.Module.merge options,
type: method
success: callback
cache: false
dataType: 'json'
- ).merge options
+ #
+ # Builds URL for current resource location
+ #
+ # @param [Object] options Handling options
+ # extension: string to add to resource base url
+ # params: GET-params to add to resulting url
+ #
@__buildSource: (options={}) ->
- unless @::hasOwnProperty '__source'
- @::__source = "/" + @entityName().pluralize()
-
- source = Joosy.buildUrl("#{@::__source}/#{options.extension || ''}", options.params)
-
- __fillData: (data) ->
- data = @__prepareData data
-
- if Object.isObject(data) && data[@constructor.entityName()] && data.keys().length == 1
- @e = Object.extended data[@constructor.entityName()]
- else
- @e = data
+ unless @hasOwnProperty '__source'
+ @__source = "/" + @::__entityName.pluralize()
+
+ source = if Object.isFunction(@__source) then @__source() else @__source
+ source = Joosy.buildUrl "#{source}/#{options.extension || ''}", options.params
\ No newline at end of file