firebase-childrenkeys
Version:
Fetch children keys of Firebase Admin Database References via the REST API
66 lines (59 loc) • 2.42 kB
JavaScript
;
const sleep = require('sleep-promise');
/**
* Fetches the keys of the current reference's children without also fetching all the contents,
* using the Firebase REST API.
*
* @param {Reference} ref A Firebase database reference.
* @param {object} options An options object with the following items, all optional:
* - maxTries: the maximum number of times to try to fetch the keys, in case of transient errors
* (defaults to 1)
* - retryInterval: the number of milliseconds to delay between retries (defaults to 1000)
* @return A promise that resolves to an array of key strings.
*/
module.exports = async (ref, options = {}) => {
const refIsNonNullObject = typeof ref === 'object' && ref !== null;
if (!refIsNonNullObject || typeof ref.ref !== 'object' ||
typeof ref.ref.transaction !== 'function') {
throw new Error(
`Expected first argument passed to childrenKeys() to be a Firebase Database reference, but
got "${ref}".`
);
} else if (typeof options !== 'object' || options === null) {
throw new Error(
`Expected second argument passed to childrenKeys() to be an options object, but got
"${options}".`
);
}
// The database property exists on Reference, but not Query. Doing ref.ref ensures we are dealing
// with a Reference instance.
const accessTokenObj = await ref.ref.database.app.options.credential.getAccessToken();
const url = new URL(ref.toString() + '.json');
url.searchParams.set('shallow', 'true');
url.searchParams.set('access_token', accessTokenObj.access_token);
let tries = 0;
async function tryRequest() {
tries++;
let data;
try {
const response = await fetch(url);
data = await response.text();
if (!response.ok) throw new Error(`HTTP ${response.status}: ${data}`);
} catch (error) {
if (options.maxTries && tries < options.maxTries) {
await sleep(options.retryInterval || 1000);
return tryRequest();
}
throw error;
}
let match;
match = data.match(/"error"\s*:\s*"([^"]*)"/);
if (match) throw new Error(`Failed to fetch children keys from Firebase REST API: ${match[1]}`);
const regex = /"(.*?)"/g;
const keys = [];
// eslint-disable-next-line no-cond-assign
while (match = regex.exec(data)) keys.push(match[1]); // don't unescape keys!
return keys;
}
return tryRequest();
};