firestorm-db
Advanced tools
Comparing version 1.11.1 to 1.12.0
{ | ||
"name": "firestorm-db", | ||
"version": "1.11.1", | ||
"version": "1.12.0", | ||
"description": "Self hosted Firestore-like database with API endpoints based on micro bulk operations", | ||
@@ -45,3 +45,3 @@ "main": "src/index.js", | ||
"devDependencies": { | ||
"chai": "^4.3.10", | ||
"chai": "^4.4.1", | ||
"docdash": "^2.0.2", | ||
@@ -52,5 +52,5 @@ "form-data": "^4.0.0", | ||
"jsdoc-to-markdown": "^8.0.1", | ||
"mocha": "^10.2.0", | ||
"mocha": "^10.3.0", | ||
"nyc": "^15.1.0", | ||
"prettier": "^3.2.4", | ||
"prettier": "^3.2.5", | ||
"recursive-copy": "^2.0.14", | ||
@@ -57,0 +57,0 @@ "typescript": "^5.3.3" |
134
README.md
@@ -21,3 +21,3 @@ <div align="center"> | ||
## JavaScript Part | ||
# JavaScript Part | ||
@@ -62,3 +62,3 @@ The JavaScript [index.js](./src/index.js) file is just an [Axios](https://www.npmjs.com/package/axios) wrapper of the library. | ||
- The name of the collection as a `String`. | ||
- The method adder, which allows to inject methods to the get methods results. This would be a `Function` taking the element as an argument. | ||
- The method adder, which lets you inject methods to query results. It's implemented similarly to [`Array.prototype.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map), taking an outputted element as an argument, modifying the element with methods and data inside a callback, and returning the modified element at the end. | ||
@@ -68,7 +68,6 @@ ```js | ||
// returns a Collection instance | ||
const userCollection = firestorm.collection("users", (el) => { | ||
el.hello = function () { | ||
console.log(`${el.name} says hello!`); | ||
}; | ||
el.hello = () => console.log(`${el.name} says hello!`); | ||
// return the modified element back with the injected method | ||
return el; | ||
}); | ||
@@ -87,11 +86,12 @@ | ||
| Name | Parameters | Description | | ||
| ----------------------------- | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | ||
| sha1() | none | Get the sha1 hash of the file. Can be used to see if same file content without downloading the file. | | ||
| readRaw() | none | Returns the whole content of the JSON. ID values are injected for easier iteration, so this may be different to sha1(). | | ||
| get(id) | id: `string \| number` | Get an element from the collection. | | ||
| search(searchOptions, random) | searchOptions: `SearchOption[]` random?:`boolean \| number` | Search through the collection You can randomize the output order with random as true or a given seed. | | ||
| searchKeys(keys) | keys: `string[] \| number[]` | Search specific keys through the collection. | | ||
| select(selectOption) | selectOption: `{ field: string[] }` | Get only selected fields from the collection Essentially an upgraded version of readRaw. | | ||
| random(max, seed, offset) | max?: `integer >= -1` seed?: `integer` offset?:`integer >= 0` | Reads random entries of collection. | | ||
| Name | Parameters | Description | | ||
| ----------------------------- | ------------------------------------------------------------| --------------------------------------------------------------------------------------------------------------------- | | ||
| sha1() | none | Get the sha1 hash of the file. Can be used to see if same file content without downloading the file. | | ||
| readRaw() | none | Returns the whole content of the JSON. ID values are injected for easier iteration, so this may be different to sha1. | | ||
| get(id) | id: `string \| number` | Get an element from the collection. | | ||
| search(searchOptions, random) | searchOptions: `SearchOption[]` random?:`boolean \| number` | Search through the collection You can randomize the output order with random as true or a given seed. | | ||
| searchKeys(keys) | keys: `string[] \| number[]` | Search specific keys through the collection. | | ||
| select(selectOption) | selectOption: `{ fields: string[] }` | Get only selected fields from the collection Essentially an upgraded version of readRaw. | | ||
| values(valueOption) | valueOption: `{ field: string, flatten?: boolean }` | Get all distinct non-null values for a given key across a collection. | | ||
| random(max, seed, offset) | max?: `number >= -1` seed?: `number` offset?:`number >= 0` | Reads random entries of collection. | | ||
@@ -104,22 +104,22 @@ The search method can take one or more options to filter entries in a collection. A search option takes a `field` with a `criteria` and compares it to a `value`. You can also use the boolean `ignoreCase` option for string values. | ||
| Criteria | Types allowed | Description | | ||
| ---------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------- | | ||
| `'!='` | `boolean`, `number`, `string` | Searches if the entry field's value is different from yours | | ||
| `'=='` | `boolean`, `number`, `string` | Searches if the entry field's value is equal to yours | | ||
| `'>='` | `number`, `string` | Searches if the entry field's value is greater or equal than yours | | ||
| `'<='` | `number`, `string` | Searches if the entry field's value is equal to than yours | | ||
| `'>'` | `number`, `string` | Searches if the entry field's value is greater than yours | | ||
| `'<'` | `number`, `string` | Searches if the entry field's value is lower than yours | | ||
| `'in'` | `number`, `string` | Searches if the entry field's value is in the array of values you gave | | ||
| `'includes'` | `string` | Searches if the entry field's value includes your substring | | ||
| `'startsWith'` | `string` | Searches if the entry field's value starts with your substring | | ||
| `'endsWith'` | `string` | Searches if the entry field's value ends with your substring | | ||
| `'array-contains'` | `Array` | Searches if the entry field's array contains your value | | ||
| `'array-contains-any'` | `Array` | Searches if the entry field's array ends contains your one value of more inside your values array | | ||
| `'array-length-eq'` | `number` | Searches if the entry field's array size is equal to your value | | ||
| `'array-length-df'` | `number` | Searches if the entry field's array size is different from your value | | ||
| `'array-length-lt'` | `number` | Searches if the entry field's array size is lower than your value | | ||
| `'array-length-gt'` | `number` | Searches if the entry field's array size is lower greater than your value | | ||
| `'array-length-le'` | `number` | Searches if the entry field's array size is lower or equal to your value | | ||
| `'array-length-ge'` | `number` | Searches if the entry field's array size is greater or equal to your value | | ||
| Criteria | Types allowed | Description | | ||
| ---------------------- | ----------------------------- | --------------------------------------------------------------------------------- | | ||
| `'!='` | `boolean`, `number`, `string` | Entry field's value is different from yours | | ||
| `'=='` | `boolean`, `number`, `string` | Entry field's value is equal to yours | | ||
| `'>='` | `number`, `string` | Entry field's value is greater or equal than yours | | ||
| `'<='` | `number`, `string` | Entry field's value is equal to than yours | | ||
| `'>'` | `number`, `string` | Entry field's value is greater than yours | | ||
| `'<'` | `number`, `string` | Entry field's value is lower than yours | | ||
| `'in'` | `number`, `string` | Entry field's value is in the array of values you gave | | ||
| `'includes'` | `string` | Entry field's value includes your substring | | ||
| `'startsWith'` | `string` | Entry field's value starts with your substring | | ||
| `'endsWith'` | `string` | Entry field's value ends with your substring | | ||
| `'array-contains'` | `Array` | Entry field's array contains your value | | ||
| `'array-contains-any'` | `Array` | Entry field's array ends contains your one value of more inside your values array | | ||
| `'array-length-eq'` | `number` | Entry field's array size is equal to your value | | ||
| `'array-length-df'` | `number` | Entry field's array size is different from your value | | ||
| `'array-length-lt'` | `number` | Entry field's array size is lower than your value | | ||
| `'array-length-gt'` | `number` | Entry field's array size is lower greater than your value | | ||
| `'array-length-le'` | `number` | Entry field's array size is lower or equal to your value | | ||
| `'array-length-ge'` | `number` | Entry field's array size is greater or equal to your value | | ||
@@ -130,3 +130,3 @@ ### Write operations | ||
| ----------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------- | | ||
| writeRaw() | none | Set the entire JSON file contents **/!\\ Very dangerous /!\\** | | ||
| writeRaw() | none | Set the entire JSON file contents **⚠️ Very dangerous! ⚠️** | | ||
| add(value) | value: `Object` | Adds one element with autoKey into the collection | | ||
@@ -143,21 +143,21 @@ | addBulk(values) | value: `Object[]` | Adds multiple elements with autoKey into the collection | | ||
Edit objects have an `id` to get the wanted element, a `field` they want to edit, an `operation` with what to do to this field, and a possible `value`. Here is a list of operations: | ||
Edit objects have an `id` of the element, a `field` to edit, an `operation` with what to do to this field, and a possible `value`. Here is a list of operations: | ||
| Operation | Value required | Types allowed | Description | | ||
| -------------- | -------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `set` | Yes | `any` | Sets a field to a given value | | ||
| `remove` | No | `any` | Removes a field from the element | | ||
| `append` | Yes | `string` | Appends string at the end of the string field | | ||
| `invert` | No | `any` | Inverts tate of boolean field | | ||
| `increment` | No | `number` | Adds a number to the field, default is 1 | | ||
| `decrement` | No | `number` | Retrieves a number to the field, default is -1 | | ||
| `array-push ` | Yes | `any` | Push an element to the end of an array field | | ||
| `array-delete` | Yes | `integer` | Removes and element at a certain index in an array field, check [array_splice documentation](https://www.php.net/manual/function.array-splice) offset for more infos | | ||
| `array-splice` | Yes | `[integer, integer]` | Removes certain elements, check [array_splice documentation](https://www.php.net/manual/function.array-splice) offset and length for more infos | | ||
| Operation | Needs value | Types allowed | Description | | ||
| -------------- | ----------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `set` | Yes | `any` | Sets a field to a given value. | | ||
| `remove` | No | `any` | Removes a field from the element. | | ||
| `append` | Yes | `string` | Appends a new string at the end of the string field. | | ||
| `invert` | No | `any` | Inverts the state of a boolean field. | | ||
| `increment` | No | `number` | Adds a number to the field, default is 1. | | ||
| `decrement` | No | `number` | Removes a number from the field, default is 1. | | ||
| `array-push ` | Yes | `any` | Push an element to the end of an array field. | | ||
| `array-delete` | Yes | `number` | Removes an element at a certain index in an array field. Check the PHP [array_splice](https://www.php.net/manual/function.array-splice) offset for more info. | | ||
| `array-splice` | Yes | `[number, number]` | Removes certain elements. Check the PHP [array_splice](https://www.php.net/manual/function.array-splice) offset and length for more info. | | ||
<br> | ||
## PHP files | ||
# PHP Part | ||
The PHP files are the ones handling files, read and writes. They also handle GET and POST requests to manipulate the database. | ||
The PHP files are the ones handling files, read and writes. They also handle `GET` and `POST` requests to manipulate the database. | ||
@@ -197,3 +197,3 @@ ## PHP setup | ||
## Files feature | ||
## Firestorm Files | ||
@@ -209,3 +209,3 @@ File API functions are detailed in the `files.php` PHP script. If you do not want to include this functionality, then just delete this file. | ||
// subfolder of uploads location, must start with dirname($_SERVER['SCRIPT_FILENAME']) | ||
// to force a subfolder of firestorm installation | ||
// to force a subfolder of Firestorm installation | ||
$STORAGE_LOCATION = dirname($_SERVER['SCRIPT_FILENAME']) . '/uploads/'; | ||
@@ -246,8 +246,4 @@ ``` | ||
uploadPromise | ||
.then(() => { | ||
console.log("Upload successful"); | ||
}) | ||
.catch((err) => { | ||
consoler.error(err); | ||
}); | ||
.then(() => console.log("Upload successful")) | ||
.catch((err) => console.error(err)); | ||
``` | ||
@@ -266,8 +262,4 @@ | ||
getPromise | ||
.then((fileContent) => { | ||
console.log(fileContent); // 'but your kids are gonna love it. | ||
}) | ||
.catch((err) => { | ||
console.error(err); | ||
}); | ||
.then((fileContent) => console.log(fileContent)) // 'but your kids are gonna love it. | ||
.catch((err) => console.error(err)); | ||
``` | ||
@@ -287,8 +279,4 @@ | ||
deletePromise | ||
.then(() => { | ||
console.log("File successfully deleted"); | ||
}) | ||
.catch((err) => { | ||
console.error(err); | ||
}); | ||
.then(() => console.log("File successfully deleted")) | ||
.catch((err) => console.error(err)); | ||
``` | ||
@@ -305,3 +293,3 @@ | ||
If you encounter a memory allocation issue, you have to allow more memory through this file `/etc/php/7.4/apache2/php.ini` with a bigger value here: | ||
If you encounter a memory allocation issue, you have to allow more memory through `/etc/php/7.4/apache2/php.ini` with a bigger value: | ||
@@ -314,5 +302,5 @@ ``` | ||
All Firestorm methods correspond to an equivalent Axios request to the relevant PHP file. Read requests are GET requests and write requests are POST requests with provided JSON data. | ||
All Firestorm methods correspond to an equivalent Axios request to the relevant PHP file. Read requests are `GET` requests and write requests are `POST` requests with provided JSON data. | ||
You always have the same first keys and the one key per method: | ||
The first keys in the request will always be the same: | ||
@@ -319,0 +307,0 @@ ```json |
286
src/index.js
@@ -7,6 +7,6 @@ try { | ||
* @typedef {Object} SearchOption | ||
* @property {string} field - The field you want to search in | ||
* @property {"!=" | "==" | ">=" | "<=" | "<" | ">" | "in" | "includes" | "startsWith" | "endsWith" | "array-contains" | "array-contains-any" | "array-length-(eq|df|gt|lt|ge|le)" } criteria - Filter criteria | ||
* @property {string | number | boolean | Array } value - The value you want to compare | ||
* @property {boolean} ignoreCase - Ignore case on search string | ||
* @property {string} field - The field to be searched for | ||
* @property {"!=" | "==" | ">=" | "<=" | "<" | ">" | "in" | "includes" | "startsWith" | "endsWith" | "array-contains" | "array-contains-any" | "array-length-(eq|df|gt|lt|ge|le)"} criteria - Search criteria to filter results | ||
* @property {string | number | boolean | Array} value - The value to be searched for | ||
* @property {boolean} [ignoreCase] - Is it case sensitive? (default true) | ||
*/ | ||
@@ -16,11 +16,17 @@ | ||
* @typedef {Object} EditObject | ||
* @property {string | number } id - The affected element | ||
* @property {string} field - The field you want to edit | ||
* @property {"set" | "remove" | "append" | "increment" | "decrement" | "array-push" | "array-delete" | "array-splice"} operation - Wanted operation on field | ||
* @property {string | number | boolean | Array} [value] - The value you want to compare | ||
* @property {string | number} id - The affected element | ||
* @property {string} field - The field to edit | ||
* @property {"set" | "remove" | "append" | "increment" | "decrement" | "array-push" | "array-delete" | "array-splice"} operation - Operation for the field | ||
* @property {string | number | boolean | Array} [value] - The value to write | ||
*/ | ||
/** | ||
* @typedef {Object} ValueObject | ||
* @property {string} field - Field to search | ||
* @property {boolean} [flatten] - Flatten array fields? (default false) | ||
*/ | ||
/** | ||
* @typedef {Object} SelectOption | ||
* @property {Array<string>} fields - Chosen fields to eventually return | ||
* @property {Array<string>} fields - Selected fields to be returned | ||
*/ | ||
@@ -43,13 +49,12 @@ | ||
if (!_address) throw new Error("Firestorm address was not configured"); | ||
return _address + "get.php"; | ||
}; | ||
const writeAddress = () => { | ||
if (!_address) throw new Error("Firestorm address was not configured"); | ||
return _address + "post.php"; | ||
}; | ||
const fileAddress = () => { | ||
if (!_address) throw new Error("Firestorm address was not configured"); | ||
return _address + "files.php"; | ||
@@ -60,3 +65,2 @@ }; | ||
if (!_token) throw new Error("Firestorm token was not configured"); | ||
return _token; | ||
@@ -77,11 +81,6 @@ }; | ||
const __extract_data = (request) => { | ||
return new Promise((resolve, reject) => { | ||
request | ||
.then((res) => { | ||
if ("data" in res) return resolve(res.data); | ||
resolve(res); | ||
}) | ||
.catch((err) => { | ||
reject(err); | ||
}); | ||
if (!(request instanceof Promise)) request = Promise.resolve(request); | ||
return request.then((res) => { | ||
if ("data" in res) return res.data; | ||
return res; | ||
}); | ||
@@ -109,3 +108,3 @@ }; | ||
/** | ||
* Add user methods to the returned data | ||
* Add user methods to returned data | ||
* @private | ||
@@ -117,16 +116,10 @@ * @ignore | ||
__add_methods(req) { | ||
return new Promise((resolve, reject) => { | ||
req | ||
.then((el) => { | ||
if (Array.isArray(el)) { | ||
return resolve(el.map((e) => this.addMethods(e))); | ||
} | ||
if (!(req instanceof Promise)) req = Promise.resolve(req); | ||
return req.then((el) => { | ||
if (Array.isArray(el)) return el.map((el) => this.addMethods(el)); | ||
el[Object.keys(el)[0]][ID_FIELD_NAME] = Object.keys(el)[0]; | ||
el = el[Object.keys(el)[0]]; | ||
el[Object.keys(el)[0]][ID_FIELD_NAME] = Object.keys(el)[0]; | ||
el = el[Object.keys(el)[0]]; | ||
// else on the object itself | ||
return resolve(this.addMethods(el)); | ||
}) | ||
.catch((err) => reject(err)); | ||
// else on the object itself | ||
return this.addMethods(el); | ||
}); | ||
@@ -168,9 +161,7 @@ } | ||
get(id) { | ||
return this.__add_methods( | ||
this.__get_request({ | ||
collection: this.collectionName, | ||
command: "get", | ||
id: id, | ||
}), | ||
); | ||
return this.__get_request({ | ||
collection: this.collectionName, | ||
command: "get", | ||
id: id, | ||
}).then((res) => this.__add_methods(res)); | ||
} | ||
@@ -219,3 +210,3 @@ | ||
let params = { | ||
const params = { | ||
collection: this.collectionName, | ||
@@ -230,3 +221,3 @@ command: "search", | ||
} else { | ||
let seed = parseInt(random); | ||
const seed = parseInt(random); | ||
if (isNaN(seed)) | ||
@@ -236,27 +227,13 @@ return Promise.reject( | ||
); | ||
params.random = { | ||
seed: seed, | ||
}; | ||
params.random = { seed }; | ||
} | ||
} | ||
return new Promise((resolve, reject) => { | ||
let raw; | ||
this.__get_request(params) | ||
.then((res) => { | ||
const arr = []; | ||
return this.__get_request(params).then((res) => { | ||
const arr = Object.entries(res).map(([id, value]) => { | ||
value[ID_FIELD_NAME] = id; | ||
return value; | ||
}); | ||
raw = res; | ||
Object.keys(res).forEach((contribID) => { | ||
const tmp = res[contribID]; | ||
tmp[ID_FIELD_NAME] = contribID; | ||
arr.push(tmp); | ||
}); | ||
resolve(this.__add_methods(Promise.resolve(arr))); | ||
}) | ||
.catch((err) => { | ||
err.raw = raw; | ||
reject(err); | ||
}); | ||
return this.__add_methods(arr); | ||
}); | ||
@@ -273,19 +250,13 @@ } | ||
return new Promise((resolve, reject) => { | ||
this.__get_request({ | ||
collection: this.collectionName, | ||
command: "searchKeys", | ||
search: keys, | ||
}) | ||
.then((res) => { | ||
const arr = []; | ||
Object.keys(res).forEach((contribID) => { | ||
const tmp = res[contribID]; | ||
tmp[ID_FIELD_NAME] = contribID; | ||
arr.push(tmp); | ||
}); | ||
return this.__get_request({ | ||
collection: this.collectionName, | ||
command: "searchKeys", | ||
search: keys, | ||
}).then((res) => { | ||
const arr = Object.entries(res).map(([id, value]) => { | ||
value[ID_FIELD_NAME] = id; | ||
return value; | ||
}); | ||
resolve(this.__add_methods(Promise.resolve(arr))); | ||
}) | ||
.catch((err) => reject(err)); | ||
return this.__add_methods(arr); | ||
}); | ||
@@ -299,16 +270,13 @@ } | ||
readRaw() { | ||
return new Promise((resolve, reject) => { | ||
this.__get_request({ | ||
collection: this.collectionName, | ||
command: "read_raw", | ||
}) | ||
.then((data) => { | ||
Object.keys(data).forEach((key) => { | ||
data[key][ID_FIELD_NAME] = key; | ||
this.addMethods(data[key]); | ||
}); | ||
return this.__get_request({ | ||
collection: this.collectionName, | ||
command: "read_raw", | ||
}).then((data) => { | ||
// preserve as object | ||
Object.keys(data).forEach((key) => { | ||
data[key][ID_FIELD_NAME] = key; | ||
this.addMethods(data[key]); | ||
}); | ||
resolve(data); | ||
}) | ||
.catch(reject); | ||
return data; | ||
}); | ||
@@ -319,3 +287,3 @@ } | ||
* Returns the whole content of the JSON | ||
* @deprecated Use readRaw instead | ||
* @deprecated Use {@link readRaw} instead | ||
* @returns {Promise<Record<string, T>>} The entire collection | ||
@@ -335,17 +303,13 @@ */ | ||
if (!selectOption) selectOption = {}; | ||
return new Promise((resolve, reject) => { | ||
this.__get_request({ | ||
collection: this.collectionName, | ||
command: "select", | ||
select: selectOption, | ||
}) | ||
.then((data) => { | ||
Object.keys(data).forEach((key) => { | ||
data[key][ID_FIELD_NAME] = key; | ||
this.addMethods(data[key]); | ||
}); | ||
return this.__get_request({ | ||
collection: this.collectionName, | ||
command: "select", | ||
select: selectOption, | ||
}).then((data) => { | ||
Object.keys(data).forEach((key) => { | ||
data[key][ID_FIELD_NAME] = key; | ||
this.addMethods(data[key]); | ||
}); | ||
resolve(data); | ||
}) | ||
.catch(reject); | ||
return data; | ||
}); | ||
@@ -355,2 +319,23 @@ } | ||
/** | ||
* Get all distinct non-null values for a given key across a collection | ||
* @param {ValueObject} valueOption - Value options | ||
* @returns {Promise<T[]>} Array of unique values | ||
*/ | ||
values(valueOption) { | ||
if (!valueOption) return Promise.reject("Value option must be provided"); | ||
if (typeof valueOption.field !== "string") return Promise.reject("Field must be a string"); | ||
if (valueOption.flatten !== undefined && typeof valueOption.flatten !== "boolean") | ||
return Promise.reject("Flatten must be a boolean"); | ||
return this.__get_request({ | ||
collection: this.collectionName, | ||
command: "values", | ||
values: valueOption, | ||
}).then((data) => | ||
// no ID_FIELD or method injection since no ids are returned | ||
Object.values(data).filter((d) => d !== null), | ||
); | ||
} | ||
/** | ||
* Returns random max entries offsets with a given seed | ||
@@ -397,3 +382,3 @@ * @param {number} max - The maximum number of entries | ||
return Promise.resolve(data); | ||
return data; | ||
}); | ||
@@ -456,4 +441,4 @@ } | ||
* Set the entire JSON file contents | ||
* @deprecated Use {@link writeRaw} instead | ||
* @param {Record<string, T>} value - The value to write | ||
* @deprecated Use writeRaw instead | ||
* @returns {Promise<WriteConfirmation>} Write confirmation | ||
@@ -471,17 +456,10 @@ */ | ||
add(value) { | ||
return new Promise((resolve, reject) => { | ||
axios | ||
.post(writeAddress(), this.__write_data("add", value)) | ||
.then((res) => { | ||
return this.__extract_data(Promise.resolve(res)); | ||
}) | ||
.then((res) => { | ||
if (typeof res != "object" || !("id" in res) || typeof res.id != "string") | ||
throw new Error("Incorrect result"); | ||
resolve(res.id); | ||
}) | ||
.catch((err) => { | ||
reject(err); | ||
}); | ||
}); | ||
return axios | ||
.post(writeAddress(), this.__write_data("add", value)) | ||
.then((res) => this.__extract_data(res)) | ||
.then((res) => { | ||
if (typeof res != "object" || !("id" in res) || typeof res.id != "string") | ||
return Promise.reject(new Error("Incorrect result")); | ||
return res.id; | ||
}); | ||
} | ||
@@ -495,9 +473,5 @@ | ||
addBulk(values) { | ||
return new Promise((resolve, reject) => { | ||
this.__extract_data(axios.post(writeAddress(), this.__write_data("addBulk", values, true))) | ||
.then((res) => { | ||
resolve(res.ids); | ||
}) | ||
.catch(reject); | ||
}); | ||
return this.__extract_data( | ||
axios.post(writeAddress(), this.__write_data("addBulk", values, true)), | ||
).then((res) => res.ids); | ||
} | ||
@@ -550,3 +524,3 @@ | ||
* @param {EditObject} obj - The edit object | ||
* @returns {Promise<T>} The edited element | ||
* @returns {Promise<{ success: boolean }>} Edit confirmation | ||
*/ | ||
@@ -561,3 +535,3 @@ editField(obj) { | ||
* @param {EditObject[]} objArray The edit object array with operations | ||
* @returns {Promise<T[]>} The edited elements | ||
* @returns {Promise<{ success: boolean[] }>} Edit confirmation | ||
*/ | ||
@@ -581,2 +555,3 @@ editFieldBulk(objArray) { | ||
if (newValue === undefined) return readAddress(); | ||
if (!newValue.endsWith("/")) newValue += "/"; | ||
if (newValue) _address = newValue; | ||
@@ -624,3 +599,3 @@ | ||
/** | ||
* Test child object with child namespace | ||
* Firestorm file handler | ||
* @memberof firestorm | ||
@@ -632,5 +607,6 @@ * @type {Object} | ||
/** | ||
* Get file back | ||
* Get a file by its path | ||
* @memberof firestorm.files | ||
* @param {string} path - The file path wanted | ||
* @returns {Promise<any>} File contents | ||
*/ | ||
@@ -648,29 +624,33 @@ get(path) { | ||
/** | ||
* Uploads file | ||
* Upload a file | ||
* @memberof firestorm.files | ||
* @param {FormData} form - The form data with path, filename, and file | ||
* @returns {Promise<any>} HTTP response | ||
* @returns {Promise<WriteConfirmation>} Write confirmation | ||
*/ | ||
upload(form) { | ||
form.append("token", firestorm.token()); | ||
return axios.post(fileAddress(), form, { | ||
headers: { | ||
...form.getHeaders(), | ||
}, | ||
}); | ||
return __extract_data( | ||
axios.post(fileAddress(), form, { | ||
headers: { | ||
...form.getHeaders(), | ||
}, | ||
}), | ||
); | ||
}, | ||
/** | ||
* Deletes a file given its path | ||
* Deletes a file by path | ||
* @memberof firestorm.files | ||
* @param {string} path - The file path to delete | ||
* @returns {Promise<any>} HTTP response | ||
* @returns {Promise<WriteConfirmation>} Write confirmation | ||
*/ | ||
delete(path) { | ||
return axios.delete(fileAddress(), { | ||
data: { | ||
path, | ||
token: firestorm.token(), | ||
}, | ||
}); | ||
return __extract_data( | ||
axios.delete(fileAddress(), { | ||
data: { | ||
path, | ||
token: firestorm.token(), | ||
}, | ||
}), | ||
); | ||
}, | ||
@@ -677,0 +657,0 @@ }, |
export type NumberCriteria = | ||
| "==" /** test if the value is equal to the provided value */ | ||
| "!=" /** test if the value is not equal to the provided value */ | ||
| "<" /** test if the value is less than the provided value */ | ||
| "<=" /** test if the value is less than or equal to the provided value */ | ||
| ">" /** test if the value is greater than the provided value */ | ||
| ">=" /** test if the value is greater than or equal to the provided value */ | ||
| "in" /** test if the value is in the given array */; | ||
| "==" /** Value is equal to the provided value */ | ||
| "!=" /** Value is not equal to the provided value */ | ||
| "<" /** Value is less than the provided value */ | ||
| "<=" /** Value is less than or equal to the provided value */ | ||
| ">" /** Value is greater than the provided value */ | ||
| ">=" /** Value is greater than or equal to the provided value */ | ||
| "in"; /** Value is in the given array */ | ||
export type StringCriteria = | ||
| "==" /** test if the string value is equal to the provided value */ | ||
| "!=" /** test if the string value is not equal to the provided value */ | ||
| "<" /** test if the string value length is less than the provided value */ | ||
| "<=" /** test if the string value length is less than or equal to the provided value */ | ||
| ">" /** test if the string value length is greater than the provided value */ | ||
| ">=" /** test if the string value length is greater than or equal to the provided value */ | ||
| "in" /** test if the string value is in the given array */ | ||
| "includes" /** test if the string value includes the provided value */ | ||
| "contains" /** same as "includes" */ | ||
| "startsWith" /** test if the string value starts with the provided value */ | ||
| "endsWith" /** test if the string value ends with the provided value */; | ||
| "==" /** String value is equal to the provided value */ | ||
| "!=" /** String value is not equal to the provided value */ | ||
| "<" /** String value length is less than the provided value */ | ||
| "<=" /** String value length is less than or equal to the provided value */ | ||
| ">" /** String value length is greater than the provided value */ | ||
| ">=" /** String value length is greater than or equal to the provided value */ | ||
| "in" /** String value is in the given array */ | ||
| "includes" /** String value includes the provided value */ | ||
| "contains" /** Same as "includes" */ | ||
| "startsWith" /** String value starts with the provided value */ | ||
| "endsWith"; /** String value ends with the provided value */ | ||
export type ArrayCriteria = | ||
| "array-contains" /** test if the value is in the given array */ | ||
| "array-contains-any" /** test if the any value of the array is in the given array */ | ||
| "array-length-eq" /** test if the array length is equal to the provided value */ | ||
| "array-length-df" /** test if the array length is different from the provided value */ | ||
| "array-length-gt" /** test if the array length is greater than the provided value */ | ||
| "array-length-lt" /** test if the array length is less than the provided value */ | ||
| "array-length-ge" /** test if the array length is greater than or equal to the provided value */ | ||
| "array-length-le" /** test if the array length is less than or equal to the provided value */; | ||
| "array-contains" /** Value is in the given array */ | ||
| "array-contains-any" /** Any value of the array is in the given array */ | ||
| "array-length-eq" /** Array length is equal to the provided value */ | ||
| "array-length-df" /** Array length is different from the provided value */ | ||
| "array-length-gt" /** Array length is greater than the provided value */ | ||
| "array-length-lt" /** Array length is less than the provided value */ | ||
| "array-length-ge" /** Array length is greater than or equal to the provided value */ | ||
| "array-length-le"; /** Array length is less than or equal to the provided value */ | ||
export type BooleanCriteria = | ||
| "!=" /** test if the value is not equal to the provided value */ | ||
| "==" /** test if the value is equal to the provided value */; | ||
| "!=" /** Value is not equal to the provided value */ | ||
| "=="; /** Value is equal to the provided value */ | ||
export type AllCriteria = | ||
| StringCriteria /** criteria applying to strings */ | ||
| ArrayCriteria /** criteria applying to arrays */ | ||
| BooleanCriteria /** criteria applying to boolean */ | ||
| NumberCriteria /** criteria applying to numbers */; | ||
export type AnyCriteria = StringCriteria | ArrayCriteria | BooleanCriteria | NumberCriteria; | ||
@@ -46,3 +42,3 @@ export type Criteria<T> = T extends Function | ||
: | ||
| never /** methods are not allowed in the field (they are not saved in the collection JSON file) */ | ||
| never /** Methods are not allowed in the field (they are not saved in the collection JSON file) */ | ||
| T extends Array<unknown> | ||
@@ -143,9 +139,9 @@ ? ArrayCriteria | ||
[K in keyof T]: { | ||
/** the field to be searched for */ | ||
/** The field to be searched for */ | ||
field: Path<T>; | ||
/** the criteria to be used to search for the field */ | ||
/** Search criteria to filter results */ | ||
criteria: Criteria<T[K]>; | ||
/** the value to be searched for */ | ||
/** The value to be searched for */ | ||
value?: any; | ||
/** is it case sensitive? (default true) */ | ||
/** Is it case sensitive? (default true) */ | ||
ignoreCase?: boolean; | ||
@@ -155,15 +151,32 @@ }; | ||
export interface SelectOption<T> { | ||
/** Chosen fields to eventually return */ | ||
fields: Array<keyof T | "id">; | ||
export interface SelectOption<T extends any[]> { | ||
/** Selected fields to be returned */ | ||
fields: T; | ||
} | ||
export interface CollectionMethods<T> { | ||
(collectionElement: Collection<T> & T): Collection<T> & T; | ||
export interface ValueOption<K, F extends boolean> { | ||
/** Field to search */ | ||
field: K | "id"; | ||
/** Flatten array fields? (default false) */ | ||
flatten?: F; | ||
} | ||
export type NoMethods<T> = { | ||
[K in keyof T]: T[K] extends Function ? K : never; | ||
}[keyof T]; | ||
/** Add methods to found elements */ | ||
export type CollectionMethods<T> = (collectionElement: T) => T; | ||
/** Remove methods from a type */ | ||
export type RemoveMethods<T> = Pick< | ||
T, | ||
{ | ||
[K in keyof T]: T[K] extends Function ? never : K; | ||
}[keyof T] | ||
>; | ||
/** ID field not known at add time */ | ||
export type Addable<T> = Omit<RemoveMethods<T>, "id">; | ||
/** ID field can be provided in request */ | ||
export type Settable<T> = Addable<T> & { | ||
id?: number | string; | ||
}; | ||
export class Collection<T> { | ||
@@ -198,3 +211,3 @@ /** | ||
public search( | ||
options: SearchOption<T & { id: string | number }>[], | ||
options: SearchOption<RemoveMethods<T> & { id: string | number }>[], | ||
random?: boolean | number, | ||
@@ -218,3 +231,3 @@ ): Promise<T[]>; | ||
* Returns the whole content of the JSON | ||
* @deprecated Use readRaw instead | ||
* @deprecated Use {@link readRaw} instead | ||
* @returns The entire collection | ||
@@ -230,5 +243,16 @@ */ | ||
*/ | ||
public select(option: SelectOption<T>): Promise<Record<string, Partial<T>>>; | ||
public select<K extends Array<"id" | keyof T>>( | ||
option: SelectOption<K>, | ||
): Promise<Record<string, Pick<T & { id: string | number }, K[number]>>>; | ||
/** | ||
* Get all distinct non-null values for a given key across a collection | ||
* @param option - Value options | ||
* @returns Array of unique values | ||
*/ | ||
public values<K extends keyof RemoveMethods<T>, F extends boolean = false>( | ||
option: ValueOption<K, F>, | ||
): Promise<T[K] extends Array<any> ? (F extends true ? T[K] : T[K][]) : T[K][]>; | ||
/** | ||
* Get random max entries offset with a given seed | ||
@@ -247,11 +271,11 @@ * @param max - The maximum number of entries | ||
*/ | ||
public writeRaw(value: Record<string, T>): Promise<WriteConfirmation>; | ||
public writeRaw(value: Record<string, RemoveMethods<T>>): Promise<WriteConfirmation>; | ||
/** | ||
* Set the entire JSON file contents | ||
* @deprecated Use writeRaw instead | ||
* @deprecated Use {@link writeRaw} instead | ||
* @param value - The value to write | ||
* @returns Write confirmation | ||
*/ | ||
public write_raw(value: Record<string, T>): Promise<WriteConfirmation>; | ||
public write_raw(value: Record<string, RemoveMethods<T>>): Promise<WriteConfirmation>; | ||
@@ -263,3 +287,3 @@ /** | ||
*/ | ||
public add(value: Writable<T>): Promise<string>; | ||
public add(value: Addable<T>): Promise<string>; | ||
@@ -271,3 +295,3 @@ /** | ||
*/ | ||
public addBulk(values: Writable<T>[]): Promise<string[]>; | ||
public addBulk(values: Addable<T>[]): Promise<string[]>; | ||
@@ -294,3 +318,3 @@ /** | ||
*/ | ||
public set(id: string | number, value: Writable<T>): Promise<WriteConfirmation>; | ||
public set(id: string | number, value: Settable<T>): Promise<WriteConfirmation>; | ||
@@ -303,3 +327,3 @@ /** | ||
*/ | ||
public setBulk(ids: string[] | number[], values: Writable<T>[]): Promise<WriteConfirmation>; | ||
public setBulk(ids: string[] | number[], values: Settable<T>[]): Promise<WriteConfirmation>; | ||
@@ -309,5 +333,5 @@ /** | ||
* @param edit - The edit object | ||
* @returns The edited element | ||
* @returns Edit confirmation | ||
*/ | ||
public editField(edit: EditField<T>): Promise<T>; | ||
public editField(edit: EditField<RemoveMethods<T>>): Promise<{ success: boolean }>; | ||
@@ -317,5 +341,5 @@ /** | ||
* @param edits - The edit objects | ||
* @returns The edited elements | ||
* @returns Edit confirmation | ||
*/ | ||
public editFieldBulk(edits: EditField<T>[]): Promise<T[]>; | ||
public editFieldBulk(edits: EditField<RemoveMethods<T>>[]): Promise<{ success: boolean[] }>; | ||
} | ||
@@ -326,5 +350,2 @@ | ||
// don't need ID field when adding keys, and setting keys has a separate ID argument | ||
type Writable<T> = Omit<Omit<T, NoMethods<T>>, "id">; | ||
/** | ||
@@ -364,4 +385,5 @@ * Change the current Firestorm address | ||
/** | ||
* Get file back | ||
* Get a file by its path | ||
* @param path - The file path wanted | ||
* @returns File contents | ||
*/ | ||
@@ -371,14 +393,14 @@ get(path: string): Promise<any>; | ||
/** | ||
* Upload file | ||
* Upload a file | ||
* @param form - The form data with path, filename, and file | ||
* @returns HTTP response | ||
* @returns Write confirmation | ||
*/ | ||
upload(form: FormData): Promise<any>; | ||
upload(form: FormData): Promise<WriteConfirmation>; | ||
/** | ||
* Deletes a file given its path | ||
* Deletes a file by path | ||
* @param path - The file path to delete | ||
* @returns HTTP response | ||
* @returns Write confirmation | ||
*/ | ||
delete(path: string): Promise<any>; | ||
delete(path: string): Promise<WriteConfirmation>; | ||
}; | ||
@@ -385,0 +407,0 @@ |
51428
931
301