From 704296c15a4f19bf0c5ee62d5a49f8b108715e37 Mon Sep 17 00:00:00 2001 From: sdenoux Date: Thu, 11 Oct 2018 13:47:35 +0200 Subject: [PATCH 1/5] Version HAL du module METHAL --- README.md | 111 ++++++++++++++++++++++++++++++++ index.js | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 52 +++++++++++++++ 3 files changed, 342 insertions(+) create mode 100644 README.md create mode 100644 index.js create mode 100644 package.json diff --git a/README.md b/README.md new file mode 100644 index 0000000..9330bda --- /dev/null +++ b/README.md @@ -0,0 +1,111 @@ +# MetHAL + +Wrapper around the HAL API. It allows to query the HAL database in a convenient way. + +## Install +```bash + npm install --save methal +``` + +## Usage +```javascript + var methal = require('methal'); + + methal.query({ docid: '19' }, { fields: '*' }, function (err, result) { + console.log(result); + }); +``` + +## Methods +### query(search, [options,] callback) +Perform a query and get the JSON response from the API. The callback is called with a potential error and the result object. (see below) + +#### Result example +```javascript +{ + "response":{ + // number of documents that match the query + "numFound": 1, + // index of the first document + "start": 0, + // actual documents (NB: the amount is limited by default) + "docs":[{ + "docid": 19, + "uri_s": "https://hal.archives-ouvertes.fr/hal-00000019", + "label_s": "Mark Wexler, Francesco Panerai, Ivan Lamouret, Jacques Droulez. Self-motion and the perception of stationary objects. Nature, Nature Publishing Group, 2001, 409, pp.85-88. <hal-00000019>" + }] + } +} +``` + +### find(search, [options,] callback) +Shorthand function to get multiple documents. Returns only the docs instead of the full JSON. + +### findOne(search, [options,] callback) +Shorthand function to get a single document. Limit the query to one row and returns only the doc instead of the full JSON. + +## Querying +The `search` can be eiter an object or a raw query string that use Solr syntax. The object supports `$and`, `$or` and `$not` operators between fields. + +Have a look at the [API documentation](http://api.archives-ouvertes.fr/docs/search/schema/fields/#fields) to get a list of all available fields. + +### Query examples +```javascript +// city contains "Paris" +{ city_t: 'paris' } +``` +```javascript +// city equals "Paris" +{ city_s: 'Paris' } +``` +```javascript +// city contains either "Paris" or "London" +{ city_t: 'paris OR london' } +``` +```javascript +// title contains "milk" and (city equals "London" or language equals "en") +{ + title_t: 'milk', + $or: [ + { city_s: 'London' }, + { language_s: 'en' } + ] +} +``` +```javascript +// city equals "Paris" and (language is not "fr" and fulltext does not contain "milk") +{ + { city_s: 'Paris' }, + $not: [ + { language_s: 'fr' }, + { fulltext_t: 'milk' } + ] +} +``` + +## Main options + +Have a look at the [API documentation](http://api.archives-ouvertes.fr/docs/search/#sort) to get a full list of available options. + + + + + + + + + + + + + + + + + + + + + + +
OptionDescription
sortSort results. Ex: "city_s asc", "language_s desc"
startOffset of the first document to return.
rowsNumber of documents to return (limited by default).
fl / fieldsFields to return. Ex: "*", "docid, country_s", ["docid", "country_s"]
diff --git a/index.js b/index.js new file mode 100644 index 0000000..e61f373 --- /dev/null +++ b/index.js @@ -0,0 +1,179 @@ +'use strict'; + +var request = require('request').defaults({ + proxy: process.env.http_proxy || + process.env.HTTP_PROXY || + process.env.https_proxy || + process.env.HTTPS_PROXY +}); + +/** + * Build a (sub)query string from search options + * @param {Object} options search options + * @param {String} operator operator to use between options, ie. AND/OR + * @return {String} solr compliant query string + */ +function buildQuery(search, operator) { + search = search || {}; + operator = operator || 'AND'; + + var parts = []; + var negation; // NOT subquery + + if (Array.isArray(search)) { + search.forEach(function (subquery) { + var part = buildQuery(subquery, 'AND'); + if (part) { parts.push(part); } + }); + } else { + var subquery; + + for (var p in search) { + switch (p) { + case '$or': + subquery = buildQuery(search[p], 'OR'); + if (subquery) { parts.push(subquery); } + break; + case '$and': + subquery = buildQuery(search[p], 'AND'); + if (subquery) { parts.push(subquery); } + break; + case '$not': + subquery = buildQuery(search.$not, 'OR'); + if (subquery) { negation = 'NOT(' + subquery + ')'; } + break; + default: + parts.push(p + ':' + search[p].toString()); + } + } + } + + if (parts.length === 0) { + return negation || ''; + } + + if (parts.length > 1 || negation) { + var query = negation ? negation + operator + '(' : '('; + return (query += parts.join(')' + operator + '(') + ')'); + } + + return parts[0]; +} + +/** + * Shorthand function to get multiple docs + * @param {Object} options + * @param {Function} callback(err, docs) + */ +exports.find = function (core, search, options, callback) { + + if (typeof options === 'function') { + callback = options; + options = {}; + } + + exports.query(core, search, options, function (err, result) { + if (err) { return callback(err); } + + if (result.response && Array.isArray(result.response.docs)) { + callback(null, result.response.docs); + } else { + callback(new Error('unexpected result, documents not found')); + } + }); +}; + +/** + * Shorthand function to get one doc + * @param {Object} search + * @param {Object} options + * @param {Function} callback(err, docs) + */ +exports.findOne = function (core, search, options, callback) { + options = options || {}; + + if (typeof options === 'function') { + callback = options; + options = {}; + } + + options.rows = 1; + + exports.query(core, search, options, function (err, result) { + if (err) { return callback(err); } + + if (result.response && Array.isArray(result.response.docs)) { + callback(null, result.response.docs[0]); + } else { + callback(new Error('unexpected result, documents not found')); + } + }); +}; + +/** + * Query HAL and get results + * @param {Object} search the actual query parameters + * @param {Object} options proxy and query options (sort, rows, fl...) + * @param {Function} callback(err, result) + */ +exports.query = function (core, search, options, callback) { + options = options || {}; + + if (typeof options === 'function') { + callback = options; + options = {}; + } + + var query = (typeof search === 'string' ? search : buildQuery(search, 'AND') || '*:*'); + + var requestOptions = {}; + if (options.hasOwnProperty('proxy')) { + requestOptions.proxy = options.proxy; + delete options.proxy; + } + + // query link + //var url = 'http://api.archives-ouvertes.fr/search/?wt=json&q=' + encodeURIComponent(query); + var url = 'http://ccsdsolrvip.in2p3.fr:8080/solr/'+ core +'/select?&wt=json&q=' + encodeURIComponent(query); + + // for convenience, add fields as an alias for fl + if (options.fields) { + options.fl = options.fields; + delete options.fields; + } + // for convenience, convert fl to string if it's an array + if (Array.isArray(options.fl)) { + options.fl = options.fl.join(','); + } + + // append options to the query (ex: start=1, rows=10) + for (var p in options) { + url += '&' + p + '=' + options[p]; + } + + request.get(url, requestOptions, function (err, res, body) { + if (err) { return callback(err); } + + if (res.statusCode !== 200) { + return callback(new Error('unexpected status code : ' + res.statusCode)); + } + + var info; + + try { + info = JSON.parse(body); + } catch(e) { + return callback(e); + } + + // if an error is thown, the json should contain the status code and a detailed message + if (info.error) { + var error = new Error(info.error.msg || 'got an unknown error from the API'); + error.code = info.error.code; + return callback(error) ; + } + + callback(null , info); + }); +}; + diff --git a/package.json b/package.json new file mode 100644 index 0000000..4675770 --- /dev/null +++ b/package.json @@ -0,0 +1,52 @@ +{ + "_args": [ + [ + "methal@2.0.2", + "/home/sdenoux/Projects/ezpaarse-brandnew" + ] + ], + "_from": "methal@2.0.2", + "_id": "methal@2.0.2", + "_inBundle": false, + "_integrity": "sha1-v6D9GehJkHnbY99z78QkhKohmQ0=", + "_location": "/methal", + "_phantomChildren": {}, + "_requested": { + "type": "version", + "registry": true, + "raw": "methal@2.0.2", + "name": "methal", + "escapedName": "methal", + "rawSpec": "2.0.2", + "saveSpec": null, + "fetchSpec": "2.0.2" + }, + "_requiredBy": [ + "/" + ], + "_resolved": "https://registry.npmjs.org/methal/-/methal-2.0.2.tgz", + "_spec": "2.0.2", + "_where": "/home/sdenoux/Projects/ezpaarse-brandnew", + "author": { + "name": "ezPAARSE Team" + }, + "bugs": { + "url": "https://github.com/aloukili/MetHAL/issues" + }, + "dependencies": { + "request": "^2.57.0" + }, + "description": "Wrapper around the HAL API.", + "homepage": "https://github.com/aloukili/MetHAL#readme", + "license": "ISC", + "main": "index.js", + "name": "methal", + "repository": { + "type": "git", + "url": "git+https://github.com/aloukili/MetHAL.git" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "version": "2.0.2" +} From 15cce2d135d49871ec064e28fe91eeeaa630798e Mon Sep 17 00:00:00 2001 From: Benoit Legouy Date: Tue, 7 Feb 2023 11:48:05 +0100 Subject: [PATCH 2/5] fix api url --- README.md | 2 +- index.js | 22 ++++++++++++-------- package.json | 57 ++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 61 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 9c53bc7..9330bda 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Wrapper around the HAL API. It allows to query the HAL database in a convenient ## Install ```bash - npm install --save @ezpaarse-project/methal + npm install --save methal ``` ## Usage diff --git a/index.js b/index.js index 48abba7..25fb2d2 100644 --- a/index.js +++ b/index.js @@ -3,6 +3,8 @@ const axios = require('axios'); const { Readable } = require('stream'); const querystring = require('querystring'); +const request = require('request'); + /** * Build a (sub)query string from search options * @param {Object} options search options @@ -28,15 +30,15 @@ function buildQuery (search, operator) { switch (p) { case '$or': subquery = buildQuery(search[p], 'OR'); - if (subquery) parts.push(subquery); + if (subquery) { parts.push(subquery); } break; case '$and': subquery = buildQuery(search[p], 'AND'); - if (subquery) parts.push(subquery); + if (subquery) { parts.push(subquery); } break; case '$not': subquery = buildQuery(search.$not, 'OR'); - if (subquery) negation = `NOT(${subquery})`; + if (subquery) { negation = `NOT(${subquery})`; } break; default: parts.push(`${p}:${search[p].toString()}`); @@ -70,7 +72,7 @@ exports.find = function (search, options, callback) { } exports.query(search, options, function (err, result) { - if (err) return callback(err); + if (err) { return callback(err); } if (result.response && Array.isArray(result.response.docs)) { callback(null, result.response.docs); @@ -130,9 +132,13 @@ exports.query = function (search, options, callback) { } // query link - let url = options.core - ? `http://ccsdsolrvip.in2p3.fr:8080/solr/${options.core}/select?&wt=json&q=${encodeURIComponent(query)}` - : `http://api.archives-ouvertes.fr/search/?wt=json&q=${encodeURIComponent(query)}`; +// let url = options.core +// ? `http://ccsdsolrvip.in2p3.fr:8080/solr/${options.core}/select?&wt=json&q=${encodeURIComponent(query)}` +// : `http://api.archives-ouvertes.fr/search/?wt=json&q=${encodeURIComponent(query)}`; + + let url = (!options.core || options.core == 'hal') + ? `http://ccsdsolrnodevipint.in2p3.fr:8983/solr/hal/apiselectall?wt=json&q=${encodeURIComponent(query)}` + : `http://api.archives-ouvertes.fr/${options.core}?wantDeprecated=true`; // for convenience, add fields as an alias for fl if (options.fields) { @@ -146,7 +152,7 @@ exports.query = function (search, options, callback) { // append options to the query (ex: start=1, rows=10) for (const p in options) { - url += `&${p}=${options[p]}`; + if (p !== 'core') { url += `&${p}=${options[p]}` }; } axios.get(url, requestOptions).then(response => { if (response.status !== 200) { diff --git a/package.json b/package.json index 5dde379..f0219ed 100644 --- a/package.json +++ b/package.json @@ -1,23 +1,58 @@ { - "name": "@ezpaarse-project/methal", - "version": "2.2.0", + "_args": [ + [ + "@ezpaarse-project/methal@2.1.0", + "/sites/ezpaarse/middlewares" + ] + ], + "_from": "@ezpaarse-project/methal@2.1.0", + "_id": "@ezpaarse-project/methal@2.1.0", + "_inBundle": false, + "_integrity": "sha512-zrnI7LWzKgs7DjMoSOwWraGUnfQxMxyOcjFAFw0vyPT7xHZ3YAswRusMBxLulnqNVASeVXsPzNQRoctlIfFBYQ==", + "_location": "/@ezpaarse-project/methal", + "_phantomChildren": {}, + "_requested": { + "type": "version", + "registry": true, + "raw": "@ezpaarse-project/methal@2.1.0", + "name": "@ezpaarse-project/methal", + "escapedName": "@ezpaarse-project%2fmethal", + "scope": "@ezpaarse-project", + "rawSpec": "2.1.0", + "saveSpec": null, + "fetchSpec": "2.1.0" + }, + "_requiredBy": [ + "/" + ], + "_resolved": "https://registry.npmjs.org/@ezpaarse-project/methal/-/methal-2.1.0.tgz", + "_spec": "2.1.0", + "_where": "/sites/ezpaarse/middlewares", + "author": { + "name": "ezPAARSE Team" + }, + "bugs": { + "url": "https://github.com/ezpaarse-project/MetHAL/issues" + }, + "dependencies": { + "axios": "^0.18.0" + }, "description": "Wrapper around the HAL API.", - "main": "index.js", "engines": { "node": ">=4.0.0" }, - "scripts": { - "test": "nyc mocha" - }, + "homepage": "https://github.com/ezpaarse-project/MetHAL#readme", + "license": "ISC", + "main": "index.js", + "name": "@ezpaarse-project/methal", "repository": { "type": "git", - "url": "https://github.com/ezpaarse-project/MetHAL.git" + "url": "git+https://github.com/ezpaarse-project/MetHAL.git" }, - "author": "ezPAARSE Team", - "license": "ISC", - "dependencies": { - "axios": "^0.18.0" + "scripts": { + "test": "nyc mocha" }, + "version": "2.1.0", "devDependencies": { "chai": "^4.2.0", "mocha": "^6.0.2", From afb242a1263e0cdce15586cc1fdafa1bc64b56ef Mon Sep 17 00:00:00 2001 From: Bruno Marmol Date: Fri, 17 Jan 2025 15:52:37 +0100 Subject: [PATCH 3/5] Insertion modif propose par Paul, issue de la branche merge-follow-hal Correction de la fonction query pour permettre (au CCSD) d'interroger une url interne de solr au lieu de l'api publique --- index.js | 71 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/index.js b/index.js index 25fb2d2..6f2a799 100644 --- a/index.js +++ b/index.js @@ -3,7 +3,13 @@ const axios = require('axios'); const { Readable } = require('stream'); const querystring = require('querystring'); -const request = require('request'); +const request = require("request").defaults({ + proxy: + process.env.http_proxy || + process.env.HTTP_PROXY || + process.env.https_proxy || + process.env.HTTPS_PROXY, +}); /** * Build a (sub)query string from search options @@ -13,14 +19,14 @@ const request = require('request'); */ function buildQuery (search, operator) { search = search || {}; - operator = operator || 'AND'; + operator = operator || "AND"; const parts = []; let negation; // NOT subquery if (Array.isArray(search)) { search.forEach(function (subquery) { - const part = buildQuery(subquery, 'AND'); + const part = buildQuery(subquery, "AND"); if (part) { parts.push(part); } }); } else { @@ -28,16 +34,16 @@ function buildQuery (search, operator) { for (const p in search) { switch (p) { - case '$or': - subquery = buildQuery(search[p], 'OR'); + case "$or": + subquery = buildQuery(search[p], "OR"); if (subquery) { parts.push(subquery); } break; - case '$and': - subquery = buildQuery(search[p], 'AND'); + case "$and": + subquery = buildQuery(search[p], "AND"); if (subquery) { parts.push(subquery); } break; - case '$not': - subquery = buildQuery(search.$not, 'OR'); + case "$not": + subquery = buildQuery(search.$not, "OR"); if (subquery) { negation = `NOT(${subquery})`; } break; default: @@ -47,13 +53,13 @@ function buildQuery (search, operator) { } if (parts.length === 0) { - return negation || ''; + return negation || ""; } if (parts.length > 1 || negation) { - let query = negation ? `${negation} ${operator} (` : '('; + let query = negation ? `${negation} ${operator} (` : "("; query += parts.join(`) ${operator} (`); - query += ')'; + query += ")"; return query; } @@ -66,7 +72,7 @@ function buildQuery (search, operator) { * @param {Function} callback(err, docs) */ exports.find = function (search, options, callback) { - if (typeof options === 'function') { + if (typeof options === "function") { callback = options; options = {}; } @@ -77,7 +83,7 @@ exports.find = function (search, options, callback) { if (result.response && Array.isArray(result.response.docs)) { callback(null, result.response.docs); } else { - callback(new Error('unexpected result, documents not found')); + callback(new Error("unexpected result, documents not found")); } }); }; @@ -91,7 +97,7 @@ exports.find = function (search, options, callback) { exports.findOne = function (search, options, callback) { options = options || {}; - if (typeof options === 'function') { + if (typeof options === "function") { callback = options; options = {}; } @@ -101,10 +107,14 @@ exports.findOne = function (search, options, callback) { exports.query(search, options, function (err, result) { if (err) { return callback(err); } - if (result.response && Array.isArray(result.response.docs)) { + if ( + result.response && + Array.isArray(result.response.docs) && + result.response.docs.length === 1 + ){ callback(null, result.response.docs[0]); } else { - callback(new Error('unexpected result, documents not found')); + callback(new Error("unexpected result, documents not found")); } }); }; @@ -118,12 +128,13 @@ exports.findOne = function (search, options, callback) { exports.query = function (search, options, callback) { options = options || {}; - if (typeof options === 'function') { + if (typeof options === "function") { callback = options; options = {}; } - const query = (typeof search === 'string' ? search : buildQuery(search, 'AND') || '*:*'); + const query = + typeof search === "string" ? search : buildQuery(search, "AND") || "*:*"; const requestOptions = {}; if (options.hasOwnProperty('proxy')) { @@ -132,13 +143,21 @@ exports.query = function (search, options, callback) { } // query link -// let url = options.core -// ? `http://ccsdsolrvip.in2p3.fr:8080/solr/${options.core}/select?&wt=json&q=${encodeURIComponent(query)}` -// : `http://api.archives-ouvertes.fr/search/?wt=json&q=${encodeURIComponent(query)}`; - let url = (!options.core || options.core == 'hal') - ? `http://ccsdsolrnodevipint.in2p3.fr:8983/solr/hal/apiselectall?wt=json&q=${encodeURIComponent(query)}` - : `http://api.archives-ouvertes.fr/${options.core}?wantDeprecated=true`; + const publicApi = "http://api.archives-ouvertes.fr"; + // const privateApiUrl = options.privateApiUrl || null; + const privateApiUrl = 'http://ccsdsolrnodevipint.in2p3.fr:8983/solr/hal/apiselectall'; + + let url ; + if (options.core === 'hal') { + if (privateApiUrl) { + url = `${privateApiUrl}?wt=json&q=${encodeURIComponent(query)}` + } else { + url = `${publicApi}/search?wt=json&q=${encodeURIComponent(query)}`; + } + } else { + url = `${publicApi}/${options.core}?${options.arg}` + } // for convenience, add fields as an alias for fl if (options.fields) { @@ -147,7 +166,7 @@ exports.query = function (search, options, callback) { } // for convenience, convert fl to string if it's an array if (Array.isArray(options.fl)) { - options.fl = options.fl.join(','); + options.fl = options.fl.join(","); } // append options to the query (ex: start=1, rows=10) From ce1bc47e895eb4ffbbde5305f4e9e06d6c973e0c Mon Sep 17 00:00:00 2001 From: Bruno Marmol Date: Fri, 17 Jan 2025 16:32:54 +0100 Subject: [PATCH 4/5] Fix ApiHalStream pour acceder a l'url interne --- index.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/index.js b/index.js index 6f2a799..96e6139 100644 --- a/index.js +++ b/index.js @@ -3,13 +3,6 @@ const axios = require('axios'); const { Readable } = require('stream'); const querystring = require('querystring'); -const request = require("request").defaults({ - proxy: - process.env.http_proxy || - process.env.HTTP_PROXY || - process.env.https_proxy || - process.env.HTTPS_PROXY, -}); /** * Build a (sub)query string from search options @@ -191,10 +184,12 @@ class ApiHalStream extends Readable { q: '*' } ) { + const publicApi = "http://api.archives-ouvertes.fr/search"; + const privateApiUrl = 'http://ccsdsolrnodevipint.in2p3.fr:8983/solr/hal/apiselectall'; super({ objectMode: true }); this.reading = false; this.counter = 0; - this.urlBase = 'http://api.archives-ouvertes.fr/search'; + this.urlBase = privateApiUrl; this.params = options; this.params.sort = 'docid asc'; this.params.cursorMark = '*'; From 349884c1487c90f2b4f70881270d0a75795e695b Mon Sep 17 00:00:00 2001 From: Bruno Marmol Date: Thu, 23 Jan 2025 16:45:21 +0100 Subject: [PATCH 5/5] Fix ccsd pour Methal: notamment utilisation d'une url interne --- index.js | 76 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/index.js b/index.js index 48abba7..be90fb8 100644 --- a/index.js +++ b/index.js @@ -2,6 +2,8 @@ const axios = require('axios'); const { Readable } = require('stream'); const querystring = require('querystring'); +const config= ezpaarse.config; + /** * Build a (sub)query string from search options @@ -11,14 +13,14 @@ const querystring = require('querystring'); */ function buildQuery (search, operator) { search = search || {}; - operator = operator || 'AND'; + operator = operator || "AND"; const parts = []; let negation; // NOT subquery if (Array.isArray(search)) { search.forEach(function (subquery) { - const part = buildQuery(subquery, 'AND'); + const part = buildQuery(subquery, "AND"); if (part) { parts.push(part); } }); } else { @@ -26,17 +28,17 @@ function buildQuery (search, operator) { for (const p in search) { switch (p) { - case '$or': - subquery = buildQuery(search[p], 'OR'); - if (subquery) parts.push(subquery); + case "$or": + subquery = buildQuery(search[p], "OR"); + if (subquery) { parts.push(subquery); } break; - case '$and': - subquery = buildQuery(search[p], 'AND'); - if (subquery) parts.push(subquery); + case "$and": + subquery = buildQuery(search[p], "AND"); + if (subquery) { parts.push(subquery); } break; - case '$not': - subquery = buildQuery(search.$not, 'OR'); - if (subquery) negation = `NOT(${subquery})`; + case "$not": + subquery = buildQuery(search.$not, "OR"); + if (subquery) { negation = `NOT(${subquery})`; } break; default: parts.push(`${p}:${search[p].toString()}`); @@ -45,13 +47,13 @@ function buildQuery (search, operator) { } if (parts.length === 0) { - return negation || ''; + return negation || ""; } if (parts.length > 1 || negation) { - let query = negation ? `${negation} ${operator} (` : '('; + let query = negation ? `${negation} ${operator} (` : "("; query += parts.join(`) ${operator} (`); - query += ')'; + query += ")"; return query; } @@ -64,18 +66,18 @@ function buildQuery (search, operator) { * @param {Function} callback(err, docs) */ exports.find = function (search, options, callback) { - if (typeof options === 'function') { + if (typeof options === "function") { callback = options; options = {}; } exports.query(search, options, function (err, result) { - if (err) return callback(err); + if (err) { return callback(err); } if (result.response && Array.isArray(result.response.docs)) { callback(null, result.response.docs); } else { - callback(new Error('unexpected result, documents not found')); + callback(new Error("unexpected result, documents not found")); } }); }; @@ -89,7 +91,7 @@ exports.find = function (search, options, callback) { exports.findOne = function (search, options, callback) { options = options || {}; - if (typeof options === 'function') { + if (typeof options === "function") { callback = options; options = {}; } @@ -99,10 +101,14 @@ exports.findOne = function (search, options, callback) { exports.query(search, options, function (err, result) { if (err) { return callback(err); } - if (result.response && Array.isArray(result.response.docs)) { + if ( + result.response && + Array.isArray(result.response.docs) && + result.response.docs.length === 1 + ){ callback(null, result.response.docs[0]); } else { - callback(new Error('unexpected result, documents not found')); + callback(new Error("unexpected result, documents not found")); } }); }; @@ -116,12 +122,13 @@ exports.findOne = function (search, options, callback) { exports.query = function (search, options, callback) { options = options || {}; - if (typeof options === 'function') { + if (typeof options === "function") { callback = options; options = {}; } - const query = (typeof search === 'string' ? search : buildQuery(search, 'AND') || '*:*'); + const query = + typeof search === "string" ? search : buildQuery(search, "AND") || "*:*"; const requestOptions = {}; if (options.hasOwnProperty('proxy')) { @@ -130,9 +137,20 @@ exports.query = function (search, options, callback) { } // query link - let url = options.core - ? `http://ccsdsolrvip.in2p3.fr:8080/solr/${options.core}/select?&wt=json&q=${encodeURIComponent(query)}` - : `http://api.archives-ouvertes.fr/search/?wt=json&q=${encodeURIComponent(query)}`; + + const publicApi = config.publicHalCoreApiUrl || "http://api.archives-ouvertes.fr"; + const privateApiUrl = config.privateHalCoreApiUrl || null; + + let url ; + if (options.core === 'hal') { + if (privateApiUrl) { + url = `${privateApiUrl}?wt=json&q=${encodeURIComponent(query)}` + } else { + url = `${publicApi}/search?wt=json&q=${encodeURIComponent(query)}`; + } + } else { + url = `${publicApi}/${options.core}?${options.arg}` + } // for convenience, add fields as an alias for fl if (options.fields) { @@ -141,12 +159,12 @@ exports.query = function (search, options, callback) { } // for convenience, convert fl to string if it's an array if (Array.isArray(options.fl)) { - options.fl = options.fl.join(','); + options.fl = options.fl.join(","); } // append options to the query (ex: start=1, rows=10) for (const p in options) { - url += `&${p}=${options[p]}`; + if (p !== 'core') { url += `&${p}=${options[p]}` }; } axios.get(url, requestOptions).then(response => { if (response.status !== 200) { @@ -166,10 +184,12 @@ class ApiHalStream extends Readable { q: '*' } ) { + const publicApi = "http://api.archives-ouvertes.fr/search"; + const privateApiUrl = 'http://ccsdsolrnodevipint.in2p3.fr:8983/solr/hal/apiselectall'; super({ objectMode: true }); this.reading = false; this.counter = 0; - this.urlBase = 'http://api.archives-ouvertes.fr/search'; + this.urlBase = privateApiUrl; this.params = options; this.params.sort = 'docid asc'; this.params.cursorMark = '*';