Skip to content

Commit

Permalink
Merge pull request #154 from sosna/develop
Browse files Browse the repository at this point in the history
Merge latest v1.5.0-related changes
  • Loading branch information
sosna committed Aug 31, 2020
2 parents 92065af + cd0a8f9 commit e482bfd
Show file tree
Hide file tree
Showing 15 changed files with 290 additions and 148 deletions.
67 changes: 64 additions & 3 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,81 @@
"plugin:coffee/eslint-recommended"
],
"rules": {
"coffee/id-length": 0,
"coffee/no-await-in-loop": 1,
"no-console": 1,
"coffee/no-template-curly-in-string": 1,
"coffee/block-scoped-var": 1,
"coffee/class-methods-use-this": 1,
"coffee/complexity": 2,
"coffee/dot-notation": 1,
"coffee/guard-for-in": 1,
"coffee/no-else-return": 1,
"coffee/no-empty-function": 2,
"no-eval": 2,
"coffee/no-loop-func": 1,
"coffee/no-return-assign": 1,
"coffee/no-self-compare": 1,
"coffee/no-sequences": 1,
"coffee/no-unmodified-loop-condition": 1,
"coffee/no-unused-expressions": 1,
"no-useless-concat": 1,
"coffee/no-useless-return": 1,
"coffee/no-use-before-define": 1,

"coffee/array-bracket-newline": 1,
"coffee/array-bracket-spacing": 1,
"coffee/array-element-newline": 1,
"comma-spacing": 1,
"coffee/comma-style": 1,
"computed-property-spacing": 1,
"coffee/consistent-this": 1,
"eol-last": 1,
"coffee/function-paren-newline": 1,
"coffee/max-len": 2,
"coffee/id-length": 0,
"key-spacing": 1,
"coffee/keyword-spacing": 1,
"coffee/lines-between-class-members": 1,
"coffee/max-depth": 2,
"coffee/max-len": 2,
"max-lines": ["error", {"skipComments": true, "skipBlankLines": true}],
"coffee/max-lines-per-function": 2,
"max-nested-callbacks": 2,
"coffee/newline-per-chained-call": 1,
"no-continue": 1,
"coffee/no-lonely-if": 1,
"coffee/no-mixed-operators": 1,
"coffee/no-multiple-empty-lines": 1,
"coffee/no-negated-condition": 2,
"no-new-object": 1,
"no-tabs": 2,
"no-trailing-spaces": 2,
"coffee/no-unneeded-ternary": 2,
"coffee/no-negated-condition": 2
"coffee/no-whitespace-before-property": 1,
"coffee/object-curly-spacing": 1,
"coffee/operator-assignment": 1,
"coffee/operator-linebreak": 1,
"space-in-parens": 1,
"coffee/space-infix-ops": 1,
"coffee/space-unary-ops": 1,

"coffee/arrow-spacing": 1,
"no-duplicate-imports": 1,
"coffee/no-useless-computed-key": 1,

"coffee/no-backticks": 2,
"coffee/english-operators": 1,
"coffee/empty-func-parens": 1,
"coffee/shorthand-this": 1,
"coffee/no-private-function-fat-arrows": 1,
"coffee/no-unnecessary-double-quotes": 1,

"coffee/no-unused-modules": 1,

"coffee/export": 1,
"coffee/no-named-as-default-member": 1,
"coffee/no-deprecated--import": 1,

"coffee/no-default-export": 1,
"coffee/no-anonymous-default-export": 1
}
}
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"node": ">=10"
},
"description": "SDMX REST API client for JavaScript",
"version": "2.16.0",
"version": "2.17.0",
"main": "./lib/index.js",
"scripts": {
"prebuild": "rm -rf lib && mkdir lib",
Expand Down Expand Up @@ -54,7 +54,7 @@
"coffeescript": "2.5.1",
"eslint": "7.7.0",
"eslint-plugin-coffee": "0.1.12",
"mocha": "8.1.2",
"mocha": "8.1.3",
"nock": "13.0.4",
"nyc": "15.1.0"
},
Expand Down
10 changes: 5 additions & 5 deletions src/avail/availability-query.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,21 @@ ValidQuery =
key: (i, e) -> isValidPattern(i, SeriesKeyType, 'series key', e)
provider: (i, e) -> isValidPattern(i, MultipleProviderRefType, 'provider', e)
component: (i, e) -> isValidPattern(i, NestedNCNameIDType, 'component', e)
start: (i, e) -> !i or isValidPeriod(i, 'start period', e)
end: (i, e) -> !i or isValidPeriod(i, 'end period', e)
updatedAfter: (i, e) -> !i or isValidDate(i, 'updatedAfter', e)
start: (i, e) -> not i or isValidPeriod(i, 'start period', e)
end: (i, e) -> not i or isValidPeriod(i, 'end period', e)
updatedAfter: (i, e) -> not i or isValidDate(i, 'updatedAfter', e)
mode: (i, e) -> isValidEnum(i, AvailabilityMode, 'mode', e)
references: (i, e) -> isValidEnum(i, AvailabilityReferences, 'references', e)

isValidQuery = (q) ->
errors = []
isValid = false
for k, v of q
for own k, v of q
isValid = ValidQuery[k](v, errors)
break unless isValid
{isValid: isValid, errors: errors}

toKeyString = (dims) ->
toKeyString = (dims) ->
((if Array.isArray d then d.join('+') else d ? '') for d in dims).join('.')

toProviderString = (p) -> p.join('+')
Expand Down
30 changes: 15 additions & 15 deletions src/data/data-query.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,6 @@ defaults =
detail: DataDetail.FULL
history: false

ValidQuery =
flow: (i, e) -> isValidPattern(i, FlowRefType, 'flows', e)
key: (i, e) -> isValidPattern(i, SeriesKeyType, 'series key', e)
provider: (i, e) -> isValidPattern(i, MultipleProviderRefType, 'provider', e)
start: (i, e) -> !i or isValidPeriod(i, 'start period', e)
end: (i, e) -> !i or isValidPeriod(i, 'end period', e)
updatedAfter: (i, e) -> !i or isValidDate(i, 'updatedAfter', e)
firstNObs: (i, e) -> !i or isValidNObs(i, 'firstNObs', e)
lastNObs: (i, e) -> !i or isValidNObs(i, 'lastNObs', e)
obsDimension: (i, e) ->
!i or isValidPattern(i, NCNameIDType, 'obs dimension', e)
detail: (i, e) -> isValidEnum(i, DataDetail, 'details', e)
history: (i, e) -> isValidHistory(i, e)

isValidHistory = (input, errors) ->
valid = typeof input is 'boolean'
errors.push "#{input} is not a valid value for history. Must be true or \
Expand All @@ -36,10 +22,24 @@ isValidNObs = (input, name, errors) ->
integer" unless valid
valid

ValidQuery =
flow: (i, e) -> isValidPattern(i, FlowRefType, 'flows', e)
key: (i, e) -> isValidPattern(i, SeriesKeyType, 'series key', e)
provider: (i, e) -> isValidPattern(i, MultipleProviderRefType, 'provider', e)
start: (i, e) -> not i or isValidPeriod(i, 'start period', e)
end: (i, e) -> not i or isValidPeriod(i, 'end period', e)
updatedAfter: (i, e) -> not i or isValidDate(i, 'updatedAfter', e)
firstNObs: (i, e) -> not i or isValidNObs(i, 'firstNObs', e)
lastNObs: (i, e) -> not i or isValidNObs(i, 'lastNObs', e)
obsDimension: (i, e) ->
not i or isValidPattern(i, NCNameIDType, 'obs dimension', e)
detail: (i, e) -> isValidEnum(i, DataDetail, 'details', e)
history: (i, e) -> isValidHistory(i, e)

isValidQuery = (q) ->
errors = []
isValid = false
for k, v of q
for own k, v of q
isValid = ValidQuery[k](v, errors)
break unless isValid
{isValid: isValid, errors: errors}
Expand Down
90 changes: 44 additions & 46 deletions src/index.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ fetch = require 'isomorphic-fetch'
userAgent = 'sdmx-rest4js (https://github.com/sosna/sdmx-rest4js)'

checkStatus = (query, response) ->
throw ReferenceError "Not a valid response" unless response
throw ReferenceError 'Not a valid response' unless response
code = response.status
unless 100 <= code < 400 or (code is 404 and query.updatedAfter)
throw RangeError "Request failed with error code #{code}"

isFormat = (input, expected) ->
out = false
for v in Object.values expected
out = true if v == input
out = true if v is input
out

isDataFormat = (format) ->
Expand All @@ -60,18 +60,18 @@ isRequestedFormat = (requested, received) ->
checkMediaType = (requested, response) ->
fmt = response.headers.get('content-type')
fmt = if fmt then fmt.replace /; version=/, ';version=' else fmt
unless isDataFormat(fmt) \
or isMetadataFormat(fmt) \
or isGenericFormat(fmt) \
or isSchemaFormat(fmt)
unless isDataFormat(fmt) or \
isMetadataFormat(fmt) or \
isGenericFormat(fmt) or \
isSchemaFormat(fmt)
throw RangeError "Not an SDMX format: #{fmt}"
unless isRequestedFormat(requested, fmt)
throw RangeError "Wrong format: requested #{requested} but got #{fmt}"

addHeaders = (opts, s, type) ->
opts = opts ? {}
opts ?= {}
headers = {}
headers[key.toLowerCase()] = opts.headers[key] for key of opts.headers
headers[key.toLowerCase()] = opts.headers[key] for own key of opts.headers
unless headers.accept
headers.accept = switch type
when 'data' then s.format
Expand Down Expand Up @@ -120,8 +120,8 @@ getService = (input) ->
throw ReferenceError "#{input} is not in the list of predefined services" \
unless Service[input]
Service[input]
else if input instanceof Object \
and Object.prototype.toString.call(input) is '[object Object]'
else if input instanceof Object and \
Object.prototype.toString.call(input) is '[object Object]'
Service.from input
else
throw TypeError "Invalid type of #{input}. Expected an object or a string"
Expand Down Expand Up @@ -284,21 +284,45 @@ getUrl = (query, service) ->
throw ReferenceError 'Not a valid service' unless service
throw ReferenceError 'Not a valid query' unless query
s = getService service
q = if (query.mode? \
or (query.flow? and query.references?) \
or (query.flow? and query.component?))
q = if (query.mode? or \
(query.flow? and query.references?) or \
(query.flow? and query.component?))
getAvailabilityQuery query
else if query.flow?
getDataQuery query
else if query.resource?
getMetadataQuery query
else if query.context?
getSchemaQuery query
if q
return new UrlGenerator().getUrl q, s
else
throw Error 'Not a valid query'

throw Error 'Not a valid query' unless q
return new UrlGenerator().getUrl q, s

#
# Executes the supplied query against the supplied service and returns a
# Promise.
#
# At the difference with the request() function, request2() will
# include the response headers and additional information such as the status.
#
# @see #request for additional information about the required parameters.
#
request2 = (params...) ->
q = params[0]
s = if typeof q is 'string' then guessService q else getService params[1]
u = if typeof q is 'string' then q else getUrl q, s
o = if typeof q is 'string' then params[1] else params[2]
t = null
if u.indexOf('/data/') > -1
t = 'data'
else if u.indexOf('/schema/') > -1
t = 'schema'
else
t = 'structure'

requestOptions = addHeaders o, s, t
fetch(u, requestOptions)
.then((response) -> response)

#
# Executes the supplied query against the supplied service and returns a
# Promise.
Expand All @@ -308,7 +332,7 @@ getUrl = (query, service) ->
#
# @example Executes the supplied query against the supplied service
# sdmxrest.request({flow: 'EXR', key: 'A.CHF.EUR.SP00.A'}, 'ECB')
# .then(function(data) {console.log(data);})
# .then(function(data) {console.log(data);})
# .catch(function(error) {console.log(error);});
#
# @example Executes the supplied query against the supplied service, asking the
Expand All @@ -323,7 +347,7 @@ getUrl = (query, service) ->
#
# @example Fetches the supplied URL
# sdmxrest.request('http://sdw-wsrest.ecb.europa.eu/service/data/EXR')
# .then(function(data) {console.log(data);})
# .then(function(data) {console.log(data);})
# .catch(function(error) {console.log(error);});
#
# @example Fetches the supplied URL, asking the service to return a compressed
Expand Down Expand Up @@ -351,32 +375,6 @@ request = (params...) ->
checkStatus params[0], response
response.text())

#
# Executes the supplied query against the supplied service and returns a
# Promise.
#
# At the difference with the request() function, request2() will
# include the response headers and additional information such as the status.
#
# @see #request for additional information about the required parameters.
#
request2 = (params...) ->
q = params[0]
s = if typeof q is 'string' then guessService q else getService params[1]
u = if typeof q is 'string' then q else getUrl q, s
o = if typeof q is 'string' then params[1] else params[2]
t = null
if u.indexOf('/data/') > -1
t = 'data'
else if u.indexOf('/schema/') > -1
t = 'schema'
else
t = 'structure'

requestOptions = addHeaders o, s, t
fetch(u, requestOptions)
.then((response) -> response)

module.exports =
getService: getService
services: services
Expand Down
14 changes: 7 additions & 7 deletions src/metadata/metadata-query.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ defaults =
references: MetadataReferences.NONE
item: 'all'

canHaveItem = (query, errors) ->
allowed = query.item is 'all' or isItemScheme query.resource
errors.push "#{query.resource} is not an item scheme and therefore it is \
not possible to query by item" unless allowed
allowed

ValidQuery =
resource: (q, i, e) -> isValidEnum(i, MetadataType, 'resources', e)
agency: (q, i, e) -> isValidPattern(i, AgenciesRefType, 'agencies', e)
Expand All @@ -24,16 +30,10 @@ ValidQuery =
item: (q, i, e) -> isValidPattern(i, MultipleNestedIDType, 'items', e) and \
canHaveItem(q, e)

canHaveItem = (query, errors) ->
allowed = query.item is 'all' or isItemScheme query.resource
errors.push "#{query.resource} is not an item scheme and therefore it is \
not possible to query by item" unless allowed
allowed

isValidQuery = (query) ->
errors = []
isValid = false
for k, v of query
for own k, v of query
isValid = ValidQuery[k](query, v, errors)
break unless isValid
{isValid: isValid, errors: errors}
Expand Down
Loading

0 comments on commit e482bfd

Please sign in to comment.