Skip to content

Instantly share code, notes, and snippets.

@baio
Created June 14, 2012 16:27
Show Gist options
  • Save baio/2931322 to your computer and use it in GitHub Desktop.
Save baio/2931322 to your computer and use it in GitHub Desktop.
odataprovider multi-valued
define ["Ural/Modules/ODataFilter", "Ural/Modules/DataFilterOpts", "Ural/Libs/datajs"], (fr, frOpts) ->
class ODataProvider
@serviceHost: -> __g.serviceHost
@_parse: (item, parent)->
if item == null or item == undefined or item instanceof Date or typeof item != "object" then return item
if item.results and Array.isArray item.results
arr = item.results
if item.d && Array.isArray item.d
arr = item.d
if Array.isArray item
arr = item
if (arr) then return arr.map (i) -> ODataProvider._parse i, parent
obj = {}
for own prop of item
if prop == "__deferred"
return if _.str.endsWith parent, "s" then [] else id : __g.nullRefVal()
if prop != "__metadata"
obj[prop] = ODataProvider._parse item[prop], prop
obj
@_isDelete: (item) -> item and item.__state and item.__state.__status == "removed"
@_getEndPoint: (name, item, isIndex) ->
if item.__endPointBinding
root = item.__endPointBinding["$root"]
root = item.__endPointBinding if typeof item.__endPointBinding == "string"
if root
if typeof root == "object"
indexEndPoint = root.index
itemEndPoint = root.item
else
itemEndPoint = root
else
itemEndPoint = name.replace /^(.*)s$/, "$1"
indexEndPoint ?= itemEndPoint.pluralize()
if isIndex then indexEndPoint else itemEndPoint
@_isNew: (item) ->
item.id == null or item.id == -1
@_getKeyVal: (id) ->
if typeof id == "string" then "'#{id}'" else id
@_isObjectArray: (val) ->
Array.isArray(val) and (val.length == 0 or (typeof(val[0]) == "object" and !(val[0] instanceof Date)))
@_formatRequest: (name, item, metadata, parentName, parent, parentContentId, totalCount) ->
res = []
expnads = []
totalCount ?= 1
cid = totalCount
isDelete = ODataProvider._isDelete item
parentId = parent.id if parent
key = ODataProvider._getKeyVal item.id
parentKey = ODataProvider._getKeyVal parentId
if !isDelete
flattered = {}
for own prop of item
val = item[prop]
#if val != null and (typeof val != "object" or val instanceof Date) and !Array.isArray(val) and prop != "__endPointBinding"
if val != null and prop != "__endPointBinding" and prop != "__state" and !ODataProvider._isObjectArray val
flattered[prop] = val
if val == null
flattered[prop] = null
propVal = parent[name] if parent
isArrayProp = if propVal then ODataProvider._isObjectArray propVal #Array.isArray(propVal) and typeof(propVal[0]) == "object" and !(propVal[0] instanceof Date) else false
typeName = if isArrayProp then name.singularize() else name
itemEP = ODataProvider._getEndPoint name, item, false
indexEP = ODataProvider._getEndPoint name, item, true
if !parentName
#root item
if isDelete
data = method: "DELETE", uri: "#{indexEP}(#{key})"
else
data = if ODataProvider._isNew item then method: "POST", uri: indexEP else method: "PUT", uri: "#{indexEP}(#{key})"
else
parentName = parentName.replace /^(.*)s$/, "$1"
parIndexEP = ODataProvider._getEndPoint parentName, parent, true
#nested item
if isDelete
ref = if !isArrayProp then name else "#{name}(#{item.id})"
data = method: "DELETE", uri: "#{parIndexEP}(#{parentId})/$links/#{ref}"
else
if item.id == __g.nullRefVal() then return res
ref = if ODataProvider._isNew parent then "$#{parentContentId}" else "#{parIndexEP}(#{parentId})"
if !ODataProvider._isNew item
###here actual update of referenced item###
res.push
headers: {"Content-ID": cid}
requestUri: "#{indexEP}(#{item.id})"
method: "PUT"
data: flattered
cid++
###here update link to referenced item###
data = method: (if isArrayProp then "POST" else "PUT"), uri: "#{ref}/$links/#{name}"
flattered = uri : "#{indexEP}(#{item.id})"
else
if isArrayProp
data = method: "POST", uri: "#{ref}/#{name}"
else
res.push
headers: {"Content-ID": cid}
requestUri: indexEP
method: "POST"
data: flattered
data = method: "PUT", uri: "#{ref}/$links/#{name}"
flattered = uri : "$#{cid}"
cid++
res.push
headers: {"Content-ID": cid}
requestUri: data.uri
method: data.method
data: flattered
totalCount += res.length
if !isDelete
for own prop of item
if prop == "__state" || prop == "__parent" || prop == "__endPointBinding" then continue
val = item[prop]
epb = item.__endPointBinding[prop] if item.__endPointBinding
if Array.isArray(val)
if ODataProvider._isObjectArray val #val.length and typeof(val[0]) == "object" and !(val[0] instanceof Date)
states = item.__state[prop] if item.__state
val = val.concat states.filter((v) -> v.__status == "removed") if states
for i, ix in val
i.__state = states[ix] if states
i.__endPointBinding = epb if epb
nested = ODataProvider._formatRequest prop, i, metadata, name, item, cid, totalCount
totalCount += nested.length
res = res.concat nested
else if val != null and typeof val == "object" and !(val instanceof Date)
val.__state = item.__state[prop] if item.__state
val.__endPointBinding = epb if epb
nested = ODataProvider._formatRequest prop, val, metadata, name, item, cid, totalCount
totalCount += nested.length
res = res.concat nested
res
load: (srcName, filter, callback) ->
stt = @_getStatement srcName, filter
OData.read stt, (data) -> callback null, ODataProvider._parse(data)
_getStatement: (srcName, filter) ->
@_getSatementByODataFilter srcName, fr.convert filter
_getExpand: (srcName, expand) ->
res = frOpts.expandOpts.get srcName, expand
if res == "" then null
res ?= expand
_getOrderBy: (srcName, filter, orderby) ->
singleItemFilter = filter.match /^.*id eq .*$/ if filter
if singleItemFilter then return null
orderby ?= frOpts.orderBy.get srcName
_getSatementByODataFilter: (srcName, oDataFilter) ->
expand = @_getExpand srcName, oDataFilter.$expand
if !oDataFilter.$isAction
srcName = srcName.pluralize()
orderby = @_getOrderBy srcName, oDataFilter.$filter, oDataFilter.$orderby
srch = _u.urlAddSearch "#{ODataProvider.serviceHost()}#{srcName}",
if oDataFilter.$filter then "$filter=#{oDataFilter.$filter}",
if oDataFilter.$top then "$top=#{oDataFilter.$top}",
if oDataFilter.$skip then "$skip=#{oDataFilter.$skip}",
if expand then "$expand=#{expand}",
if orderby then "$orderby=#{orderby}"
if oDataFilter.$args
for own arg of oDataFilter.$args
srch = _u.urlAddSearch srch, "#{arg}=#{oDataFilter.$args[arg]}"
srch
@_getMetadata: (srcName, item) ->
null
@_getSaveRequestData: (srcName, item) ->
#metadata = ODataProvider._getMetadata srcName, item
if item.__parent
parentId = item.__parent.id
parentTypeName = item.__parent.typeName
req = ODataProvider._formatRequest srcName, item, null, parentTypeName, parentId
req.sort (a, b) -> a.headers["Content-ID"] - b.headers["Content-ID"]
__batchRequests: [
__changeRequests: req
]
@_getBodyError: (body) ->
xmlDoc = $.parseXML body
$xml = $(body)
#TO DO
$xml[1].children[1].textContent
@_parseSaveResponseData: (data) ->
res = []
for batchResponse in data.__batchResponses
for changeResponse in batchResponse.__changeResponses
res.push
type: null
contentId: changeResponse.headers["Content-ID"] if changeResponse.headers
data: changeResponse.data
error: changeResponse.message
bodyError : if changeResponse.response and changeResponse.response.body then ODataProvider._getBodyError changeResponse.response.body else null
res
save: (srcName, item, callback) ->
request =
requestUri: "#{ODataProvider.serviceHost()}$batch"
method: "POST"
data: ODataProvider._getSaveRequestData srcName, item
OData.request request
, (data) =>
resp = ODataProvider._parseSaveResponseData data
errs = resp.filter (f) -> f.error
if !errs.length and (!item.__state or item.__state.__status != "removed")
expand = @_getExpand srcName, "$item"
rootResp = resp.filter((x) -> x.contentId == "1")[0]
id = if rootResp and rootResp.data then rootResp.data.id else item.id
@load srcName, $filter : { id: {$eq: id}}, $expand: expand, (err, data) ->
if !err then data = data[0]
callback err, data
else
callback errs.map((err) -> if err.bodyError then err.bodyError else err.error).join '\n'
, (err) ->
callback err
, OData.batchHandler
delete: (srcName, id, callback) ->
@save srcName, {id : id, __state : {__status : "removed"} } , callback
dataProvider: new ODataProvider()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment