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