///
///
import Q from "p-queue";
declare namespace customUtils {
function uid(): string;
function randomString(len: number): string;
/**
* Return an array with the numbers from 0 to n-1, in a random order
*/
function getRandomArray(n: number): number[];
}
declare namespace model {
interface keyedObject {
[key: string]: Value;
}
type PrimitiveValue = number | string | boolean | undefined | null | Date;
type Value = keyedObject | Array | PrimitiveValue; /**
* Check a key throw an error if the key is non valid
* Non-treatable edge cases here: if part of the object if of the form { $$date: number } or { $$deleted: true }
* Its serialized-then-deserialized version it will transformed into a Date object
* But you really need to want it to trigger such behaviour, even when warned not to use '$' at the beginning of the field names...
*/
/**
* Check a key throw an error if the key is non valid
* Non-treatable edge cases here: if part of the object if of the form { $$date: number } or { $$deleted: true }
* Its serialized-then-deserialized version it will transformed into a Date object
* But you really need to want it to trigger such behaviour, even when warned not to use '$' at the beginning of the field names...
*/
/**
* Check a key throw an error if the key is non valid
* Non-treatable edge cases here: if part of the object if of the form { $$date: number } or { $$deleted: true }
* Its serialized-then-deserialized version it will transformed into a Date object
* But you really need to want it to trigger such behaviour, even when warned not to use '$' at the beginning of the field names...
*/
/**
* Check a DB object and throw an error if it's not valid
* Works by applying the above checkKey function to all fields recursively
*/
function checkObject(obj: Value): void;
/**
* Serialize an object to be persisted to a one-line string
* For serialization/deserialization, we use the native JSON parser and not eval or Function
* That gives us less freedom but data entered in the database may come from users
* so eval and the like are not safe
* Accepted primitive types: Number, String, Boolean, Date, null
* Accepted secondary types: Objects, Arrays
*/
function serialize(obj: T): string;
/**
* From a one-line representation of an object generate by the serialize function
* Return the object itself
*/
function deserialize(rawData: string): any;
/**
* Deep copy a DB object
* The optional strictKeys flag (defaulting to false) indicates whether to copy everything or only fields
* where the keys are valid, i.e. don't begin with $ and don't contain a .
*/
function deepCopy(obj: T, model: (new () => any) & {
new: (json: any) => any;
}, strictKeys?: boolean): T;
/**
* Tells if an object is a primitive type or a "real" object
* Arrays are considered primitive
*/
function isPrimitiveType(obj: Value): boolean;
/**
* Utility functions for comparing things
* Assumes type checking was already done (a and b already have the same type)
* compareNSB works for numbers, strings and booleans
*/
type NSB = number | string | boolean;
function compareNSB(a: T, b: T): 0 | 1 | -1;
function compareThings(a: V, b: V, _compareStrings?: typeof compareNSB): 0 | 1 | -1; // ==============================================================
// Updating documents
// ==============================================================
/**
* The signature of modifier functions is as follows
* Their structure is always the same: recursively follow the dot notation while creating
* the nested documents if needed, then apply the "last step modifier"
*/
// ==============================================================
// Updating documents
// ==============================================================
/**
* The signature of modifier functions is as follows
* Their structure is always the same: recursively follow the dot notation while creating
* the nested documents if needed, then apply the "last step modifier"
*/
// ==============================================================
// Updating documents
// ==============================================================
/**
* The signature of modifier functions is as follows
* Their structure is always the same: recursively follow the dot notation while creating
* the nested documents if needed, then apply the "last step modifier"
*/
/**
* Modify a DB object according to an update query
*/
function modify(obj: G, updateQuery: any, model: (new () => G) & {
new: (json: G) => G;
}): G;
// ==============================================================
// Finding documents
// ==============================================================
/**
* Get a value from object with dot notation
*/
function getDotValue(obj: any, field: string): any;
function areThingsEqual(a: A, b: B): boolean; /**
* Check that two values are comparable
*/
/**
* Check that two values are comparable
*/
/**
* Check that two values are comparable
*/
function match(obj: any, query: any): boolean; /**
* Match an object against a specific { key: value } part of a query
* if the treatObjAsValue flag is set, don't try to match every part separately, but the array as a whole
*/
/**
* Match an object against a specific { key: value } part of a query
* if the treatObjAsValue flag is set, don't try to match every part separately, but the array as a whole
*/
/**
* Match an object against a specific { key: value } part of a query
* if the treatObjAsValue flag is set, don't try to match every part separately, but the array as a whole
*/
}
declare class BaseModel {
_id: string;
updatedAt?: Date;
createdAt?: Date;
static new(this: new () => T, data: Partial>): T;
}
type NFPN = {
[K in keyof T]: T[K] extends Function ? never : K;
}[keyof T];
type NFP = Pick>;
type Keys = keyof O;
type Partial = {
[P in keyof T]?: T[P];
};
interface AnyFieldOperators {
$type?: "string" | "number" | "boolean" | "undefined" | "array" | "null" | "date" | "object";
/**
* Specifies equality condition. The $eq operator matches documents where the value of a field equals the specified value.
* {field: { $eq: }}
*/
$eq?: V;
/**
* The $in operator selects the documents where the value of a field equals any value in the specified array.
* { field: { $in: [, , ... ] } }
*/
$in?: V[];
/**
* $ne selects the documents where the value of the field is not equal (i.e. !=) to the specified value. This includes documents that do not contain the field.
* {field: {$ne:value}}
*/
$ne?: V;
/**
* $nin selects the documents where: the field value is not in the specified array or the field does not exist.
* { field: { $nin: [ , ... ]} }
*/
$nin?: V[];
/**
* $not performs a logical NOT operation on the specified and selects the documents that do not match the . This includes documents that do not contain the field.
* { field: { $not: { } } }
*/
$not?: FieldLevelQueryOperators;
/**
* When is true, $exists matches the documents that contain the field, including documents where the field value is null. If is false, the query returns only the documents that do not contain the field.
* { field: { $exists: } }
*/
$exists?: boolean;
}
interface StringOperators extends AnyFieldOperators {
/**
* Provides regular expression capabilities for pattern matching strings in queries. MongoDB uses Perl compatible regular expressions (i.e. “PCRE” ) version 8.41 with UTF-8 support.
* {field:{$regex: /pattern/}}
*/
$regex?: RegExp;
}
interface NumberOperators extends AnyFieldOperators {
/**
* $gt selects those documents where the value of the field is greater than (i.e. >) the specified value.
* {field: {$gt:value}}
*/
$gt?: V;
/**
* $gte selects the documents where the value of the field is greater than or equal to (i.e. >=) a specified value
* {field: {$gte:value}}
*/
$gte?: V;
/**
* $lt selects the documents where the value of the field is less than (i.e. <) the specified value.
* {field: {$lt:value}}
*/
$lt?: V;
/**
* $lte selects the documents where the value of the field is less than or equal to (i.e. <=) the specified value.
* {field: {$lte:value}}
*/
$lte?: V;
/**
* Select documents where the value of a field divided by a divisor has the specified remainder (i.e. perform a modulo operation to select documents). To specify a $mod expression, use the following syntax:
* { field: { $mod: [ divisor, remainder ] } }
*/
$mod?: [number, number];
}
type InnerArrayOperators = V extends Date ? NumberOperators : V extends number ? NumberOperators : V extends string ? StringOperators : AnyFieldOperators;
interface TotalArrayOperators extends AnyFieldOperators {
/**
* The $all operator selects the documents where the value of a field is an array that contains all the specified elements.
*{ field: { $all: [ , ... ] } }
*/
$all?: Array;
/**
* The $elemMatch operator matches documents that contain an array field with at least one element that matches all the specified query criteria.
* { : { $elemMatch: { , , ... } } }
*/
$elemMatch?: FieldLevelQueryOperators;
/**
* The $size operator matches any array with the number of elements specified by the argument. For example:{ field: { $size: 2 } }
*/
$size?: number;
}
type ArrayOperators = TotalArrayOperators & InnerArrayOperators;
interface TopLevelQueryOperators {
/**
* $and performs a logical AND operation on an array of two or more expressions (e.g. , , etc.) and selects the documents that satisfy all the expressions in the array. The $and operator uses short-circuit evaluation. If the first expression (e.g. ) evaluates to false, MongoDB will not evaluate the remaining expressions.
* { $and: [ { }, { } , ... , { } ] }
*/
$and?: SchemaKeyFilters[];
/**
* $nor performs a logical NOR operation on an array of one or more query expression and selects the documents that fail all the query expressions in the array. The $nor has the following syntax:
* { $nor: [ { }, { }, ... { } ] }
*/
$nor?: SchemaKeyFilters[];
/**
* The $or operator performs a logical OR operation on an array of two or more expressions and selects the documents that satisfy at least one of the expressions. The $or has the following syntax:
* { $or: [ { }, { }, ... , { } ] }
*/
$or?: SchemaKeyFilters[];
/**
* Use the $where operator to pass either a string containing a JavaScript function to the query system. The $where provides greater flexibility, but requires that the database processes the JavaScript expression or function for each document in the collection. Reference the document in the JavaScript expression or function using this.
*/
$where?: (this: S) => boolean;
/**
* Use this operator when trying to apply filter on a deeply nested properties, like: "employee.address.street".
* {$deep: {"employee.address.street": {$eq: "Bedford Mount"}}}
*/
$deep?: {
[key: string]: SchemaKeyFilters;
};
}
type FieldLevelQueryOperators = V extends Array ? ArrayOperators : V extends Date ? NumberOperators : V extends number ? NumberOperators : V extends string ? StringOperators : AnyFieldOperators;
type SchemaKeyFilters = Partial<{
[key in Keys]: FieldLevelQueryOperators | S[key];
}>;
type Filter = SchemaKeyFilters | TopLevelQueryOperators;
type SchemaKeySort = Partial<{
[key in Keys]: -1 | 1;
} & {
$deep: {
[key: string]: -1 | 1;
};
}>;
type SchemaKeyProjection = Partial<{
[key in Keys]: 0 | 1;
} & {
$deep: {
[key: string]: 0 | 1;
};
}>;
interface PushModifiers {
/**
* Modifies the $push and $addToSet operators to append multiple items for array updates.
* { ($addToSet|$push): { : { $each: [ , ... ] } } }
*/
$each: V[];
/**
* Modifies the $push operator to limit the size of updated arrays.
* {$push: {: {$each: [ , , ... ],$slice: }}}
*/
$slice?: number;
/**
* The $sort modifier orders the elements of an array during a $push operation. To use the $sort modifier, it must appear with the $each modifier.
* You can pass an empty array [] to the $each modifier such that only the $sort modifier has an effect.
* {$push: {: {$each: [ , , ... ],$sort: }}}
*/
$sort?: 1 | -1 | Partial<{
[Key in Keys]: 1 | -1;
}>;
/**
* The $position modifier specifies the location in the array at which the $push operator insert elements. Without the $position modifier, the $push operator inserts elements to the end of the array.
*/
$position?: number;
}
interface UpsertOperators extends UpdateOperators {
/**
* If an update operation with upsert: true results in an insert of a document, then $setOnInsert assigns the specified values to the fields in the document. If the update operation does not result in an insert, $setOnInsert does nothing.
* { $setOnInsert: { : , ... } },
*
*/
$setOnInsert: S;
}
interface UpdateOperators {
/**
* Increments the value of the field by the specified amount.
* { $inc: { : , : , ... } }
*/
$inc?: Partial<{
[Key in Keys]: S[Key] extends number ? number : never;
}>;
/**
* Multiplies the value of the field by the specified amount.
* { $mul: { field: } }
*/
$mul?: Partial<{
[Key in Keys]: S[Key] extends number ? number : never;
}>;
/**
* Renames a field.
* {$rename: { : , : , ... } }
*/
$rename?: UpdateOperatorsOnSchema;
/**
* Sets the value of a field in a document.
* { $set: { : , ... } }
*/
$set?: Partial;
/**
* Removes the specified field from a document.
* { $unset: { : "", ... } }
*/
$unset?: Partial<{
[key in Keys]: "";
} & {
$deep: {
[key: string]: "";
};
}>;
/**
* Only updates the field if the specified value is less than the existing field value.
* { $min: { : , ... } }
*/
$min?: Partial<{
[Key in Keys]: S[Key] extends number ? S[Key] : S[Key] extends Date ? S[Key] : never;
}>;
/**
* Only updates the field if the specified value is greater than the existing field value.
* { $max: { : , ... } }
*/
$max?: Partial<{
[Key in Keys]: S[Key] extends number ? S[Key] : S[Key] extends Date ? S[Key] : never;
}>;
/**
* Sets the value of a field to current date, either as a Date or a Timestamp.
* { $currentDate: { : , ... } }
*/
$currentDate?: Partial<{
[Key in Keys]: S[Key] extends Date ? true | {
$type: "date";
} : S[Key] extends number ? {
$type: "timestamp";
} : never;
}>;
/**
* Adds elements to an array only if they do not already exist in the set.
* { $addToSet: { : , ... } }
*/
$addToSet?: Partial<{
[Key in Keys]: S[Key] extends Array ? U | {
$each: U[];
} : never;
}>;
/**
* The $pop operator removes the first or last element of an array. Pass $pop a value of -1 to remove the first element of an array and 1 to remove the last element in an array.
* { $pop: { : <-1 | 1>, ... } }
*/
$pop?: Partial<{
[Key in Keys]: S[Key] extends Array ? -1 | 1 : never;
}>;
/**
* Removes all array elements that match a specified query.
* { $pull: { : , : , ... } }
*/
$pull?: Partial<{
[Key in Keys]: S[Key] extends Array ? Partial | FieldLevelQueryOperators : never;
}>;
/**
* The $pullAll operator removes all instances of the specified values from an existing array. Unlike the $pull operator that removes elements by specifying a query, $pullAll removes elements that match the listed values.
* { $pullAll: { : [ , ... ], ... } }
*/
$pullAll?: Partial<{
[Key in Keys]: S[Key] extends Array ? U[] : never;
}>;
/**
* The $push operator appends a specified value to an array.
* { $push: { : , ... } }
*/
$push?: Partial<{
[Key in Keys]: S[Key] extends Array ? U | PushModifiers : never;
}>;
}
type UpdateOperatorsOnSchema = Partial<{
[key in Keys]: V;
}>;
/**
* Create a new cursor for this collection
*/
declare class Cursor {
private db;
private query;
private _limit;
private _skip;
private _sort;
private _projection;
constructor(db: Datastore, query?: any);
/**
* Set a limit to the number of results
*/
limit(limit: number): this;
/**
* Skip a the number of results
*/
skip(skip: number): this;
/**
* Sort results of the query
*/
sort(sortQuery: SchemaKeySort): this;
/**
* Add the use of a projection
*/
projection(projection: SchemaKeyProjection): this;
/**
* Apply the projection
*/
private _project;
/**
* Get all matching elements
* Will return pointers to matched elements (shallow copies), returning full copies is the role of find or findOne
*
*/
__exec_unsafe(): Promise;
private _exec;
exec(): Promise;
}
declare namespace utils {
/*
* Default compareKeys function will work for numbers, strings and dates
*/
function defaultCompareKeysFunction(a: NSD, b: NSD): number;
/**
* Check whether two values are equal (used in non-unique deletion)
*/
function defaultCheckValueEquality(a: T, b: T): boolean;
function isDef(v: any): boolean;
}
interface initializationOptions {
key?: K;
value?: V;
unique?: boolean;
compareKeys?: typeof utils.defaultCompareKeysFunction;
checkValueEquality?: typeof utils.defaultCheckValueEquality;
}
interface AVLOptions extends initializationOptions {
left?: Node;
right?: Node;
parent?: Node;
}
interface BSTOptions extends initializationOptions {
left?: BST;
right?: BST;
parent?: BST;
}
declare namespace utils {
/*
* Default compareKeys function will work for numbers, strings and dates
*/
function defaultCompareKeysFunction(a: NSD, b: NSD): number;
/**
* Check whether two values are equal (used in non-unique deletion)
*/
function defaultCheckValueEquality(a: T, b: T): boolean;
function isDef(v: any): boolean;
}
/**
* Simple binary search tree
*/
declare class BST {
left: BST | undefined;
right: BST | undefined;
parent: BST | undefined;
key: K | undefined;
data: V[];
unique: boolean;
compareKeys: typeof utils.defaultCompareKeysFunction;
checkValueEquality: typeof utils.defaultCheckValueEquality;
constructor(init?: BSTOptions);
/**
* Get the descendant with max key
*/
getMaxKeyDescendant(): BST;
/**
* Get the maximum key
*/
getMaxKey(): K | undefined;
/**
* Get the descendant with min key
*/
getMinKeyDescendant(): BST;
/**
* Get the minimum key
*/
getMinKey(): K | undefined;
/**
* Check that all nodes (incl. leaves) fullfil condition given by fn
* test is a function passed every (key, data) and which throws if the condition is not met
*/
forEach(test: (key: K | undefined, value: V[]) => any): void;
/**
* Check that the core BST properties on node ordering are verified
* Throw if they aren't
*/
checkNodeOrdering(): void;
/**
* Check that all pointers are coherent in this tree
*/
checkInternalPointers(): void;
/**
* Check that a tree is a BST as defined here (node ordering and pointer references)
*/
checkIsBST(): void;
/**
* Get number of keys inserted
*/
getNumberOfKeys(): number;
// ============================================
// Methods used to actually work on the tree
// ============================================
/**
* Create a BST similar (i.e. same options except for key and value) to the current one
* Use the same constructor (i.e. BinarySearchTree, AVLTree etc)
*/
createSimilar(this: any, options?: BSTOptions): any;
/**
* Create the left child of this BST and return it
*/
createLeftChild(options: BSTOptions): any;
/**
* Create the right child of this BST and return it
*/
createRightChild(options: BSTOptions): any;
/**
* Insert a new element
*/
insert(key: K, value?: V): void;
/**
* Search for all data corresponding to a key
*/
search(key: K): V[];
/**
* Search for data coming right after a specific key
*/
searchAfter(key: K): V[];
/**
* Search for data coming right before a specific key
*/
searchBefore(key: K): V[];
/**
* Search for all data corresponding to a specific key, if that key
* does not exist, find the nearest key less than the specified key and its
* associated data. Returns undefined if no such key&data can be found.
**/
searchNearestLte(key: K): V[] | undefined;
private _searchNearestLte;
/**
* Search for all data corresponding to a specific key, if that key
* does not exist, find the nearest key greater than the specified key and its
* associated data. Returns undefined if no such key&data can be found.
**/
searchNearestGte(key: K): V[] | undefined;
private _searchNearestGte;
/**
* Search for all data corresponding to a specific key, if that key
* does not exist, find the nearest key and associated data.
*/
searchNearest(key: K): V[] | undefined;
private _searchNearest;
/**
* Return a function that tells whether a given key matches a lower bound
*/
getLowerBoundMatcher(query: any): (key: K) => boolean;
/**
* Return a function that tells whether a given key matches an upper bound
*/
getUpperBoundMatcher(query: any): (key: K) => boolean;
/**
* Get all data for a key between bounds
* Return it in key order
*/
betweenBounds(query: any, lbm: BST["getLowerBoundMatcher"], ubm: BST["getLowerBoundMatcher"]): V[];
/**
* Delete the current node if it is a leaf
* Return true if it was deleted
*/
deleteIfLeaf(): boolean;
/**
* Delete the current node if it has only one child
* Return true if it was deleted
*/
deleteIfOnlyOneChild(): boolean;
/**
* Delete a key or just a value
*/
delete(key: K, value?: V): void;
/**
* Execute a function on every node of the tree, in key order
*/
executeOnEveryNode(fn: (bst: BST) => void): void;
/**
* Pretty print a tree
*/
prettyPrint(printData: boolean, spacing?: string): void;
}
declare namespace utils {
/*
* Default compareKeys function will work for numbers, strings and dates
*/
function defaultCompareKeysFunction(a: NSD, b: NSD): number;
/**
* Check whether two values are equal (used in non-unique deletion)
*/
function defaultCheckValueEquality(a: T, b: T): boolean;
function isDef(v: any): boolean;
}
/**
* Self-balancing binary search tree using the AVL implementation
*/
declare class AVLTree {
tree: Node;
constructor(options?: AVLOptions);
checkIsAVLT(): void;
// Insert in the internal tree, update the pointer to the root if needed
insert(key: K, value: V): void;
// Delete a value
delete(key: K, value?: V): void;
getNumberOfKeys(): number;
getMinKey(): K | undefined;
getMaxKey(): K | undefined;
search(key: K): V[];
searchAfter(k: K): V[];
searchBefore(k: K): V[];
searchNearest(k: K): V[] | undefined;
searchNearestLte(k: K): V[] | undefined;
searchNearestGte(k: K): V[] | undefined;
betweenBounds(query: any, lbm?: (query: any) => (key: K) => boolean, ubm?: (query: any) => (key: K) => boolean): V[];
prettyPrint(printData: boolean, spacing?: string): void;
executeOnEveryNode(fn: (bst: BST) => void): void;
} /**
* Node
*/
/**
* Node
*/
declare class Node extends BST {
left: Node | undefined;
right: Node | undefined;
parent: Node | undefined;
key: K | undefined;
data: V[];
unique: boolean;
compareKeys: typeof utils.defaultCompareKeysFunction;
checkValueEquality: typeof utils.defaultCheckValueEquality;
height: number;
constructor(init?: AVLOptions);
/**
* Check the recorded height is correct for every node
* Throws if one height doesn't match
*/
checkHeightCorrect(): void;
/**
* Return the balance factor
*/
balanceFactor(): number;
/**
* Check that the balance factors are all between -1 and 1
*/
checkBalanceFactors(): void;
/**
* When checking if the BST conditions are met, also check that the heights are correct
* and the tree is balanced
*/
checkIsAVLT(): void;
/**
* Perform a right rotation of the tree if possible
* and return the root of the resulting tree
* The resulting tree's nodes' heights are also updated
*/
rightRotation(): Node;
/**
* Perform a left rotation of the tree if possible
* and return the root of the resulting tree
* The resulting tree's nodes' heights are also updated
*/
leftRotation(): Node;
/**
* Modify the tree if its right subtree is too small compared to the left
* Return the new root if any
*/
rightTooSmall(): Node;
/**
* Modify the tree if its left subtree is too small compared to the right
* Return the new root if any
*/
leftTooSmall(): Node;
/**
* Rebalance the tree along the given path. The path is given reversed (as he was calculated
* in the insert and delete functions).
* Returns the new root of the tree
* Of course, the first element of the path must be the root of the tree
*/
rebalanceAlongPath(path: Node[]): Node;
/**
* Insert a key, value pair in the tree while maintaining the AVL tree height constraint
* Return a pointer to the root node, which may have changed
*/
insert(key: K, value: V): Node;
/**
* Delete a key or just a value and return the new root of the tree
*/
delete(key: K, value?: V): Node;
}
declare namespace model {
interface keyedObject {
[key: string]: Value;
}
type PrimitiveValue = number | string | boolean | undefined | null | Date;
type Value = keyedObject | Array | PrimitiveValue; /**
* Check a key throw an error if the key is non valid
* Non-treatable edge cases here: if part of the object if of the form { $$date: number } or { $$deleted: true }
* Its serialized-then-deserialized version it will transformed into a Date object
* But you really need to want it to trigger such behaviour, even when warned not to use '$' at the beginning of the field names...
*/
/**
* Check a DB object and throw an error if it's not valid
* Works by applying the above checkKey function to all fields recursively
*/
function checkObject(obj: Value): void;
/**
* Serialize an object to be persisted to a one-line string
* For serialization/deserialization, we use the native JSON parser and not eval or Function
* That gives us less freedom but data entered in the database may come from users
* so eval and the like are not safe
* Accepted primitive types: Number, String, Boolean, Date, null
* Accepted secondary types: Objects, Arrays
*/
function serialize(obj: T): string;
/**
* From a one-line representation of an object generate by the serialize function
* Return the object itself
*/
function deserialize(rawData: string): any;
/**
* Deep copy a DB object
* The optional strictKeys flag (defaulting to false) indicates whether to copy everything or only fields
* where the keys are valid, i.e. don't begin with $ and don't contain a .
*/
function deepCopy(obj: T, model: (new () => any) & {
new: (json: any) => any;
}, strictKeys?: boolean): T;
/**
* Tells if an object is a primitive type or a "real" object
* Arrays are considered primitive
*/
function isPrimitiveType(obj: Value): boolean;
/**
* Utility functions for comparing things
* Assumes type checking was already done (a and b already have the same type)
* compareNSB works for numbers, strings and booleans
*/
type NSB = number | string | boolean;
function compareNSB(a: T, b: T): 0 | 1 | -1;
function compareThings(a: V, b: V, _compareStrings?: typeof compareNSB): 0 | 1 | -1; // ==============================================================
// Updating documents
// ==============================================================
/**
* The signature of modifier functions is as follows
* Their structure is always the same: recursively follow the dot notation while creating
* the nested documents if needed, then apply the "last step modifier"
*/
/**
* Modify a DB object according to an update query
*/
function modify(obj: G, updateQuery: any, model: (new () => G) & {
new: (json: G) => G;
}): G;
// ==============================================================
// Finding documents
// ==============================================================
/**
* Get a value from object with dot notation
*/
function getDotValue(obj: any, field: string): any;
function areThingsEqual(a: A, b: B): boolean; /**
* Check that two values are comparable
*/
function match(obj: any, query: any): boolean; /**
* Match an object against a specific { key: value } part of a query
* if the treatObjAsValue flag is set, don't try to match every part separately, but the array as a whole
*/
}
interface Pair {
newDoc: Doc;
oldDoc: Doc;
} /**
* Two indexed pointers are equal iif they point to the same place
*/
declare function checkValueEquality(a: T, b: T): boolean; /**
* Type-aware projection
*/
/**
* Type-aware projection
*/
/**
* Type-aware projection
*/
declare class Index> {
fieldName: string;
unique: boolean;
sparse: boolean;
treeOptions: {
unique: boolean;
compareKeys: typeof model.compareThings;
checkValueEquality: typeof checkValueEquality;
};
tree: AVLTree;
constructor({ fieldName, unique, sparse }: {
fieldName: string;
unique?: boolean;
sparse?: boolean;
});
reset(): void;
/**
* Insert a new document in the index
* If an array is passed, we insert all its elements (if one insertion fails the index is not modified)
* O(log(n))
*/
insert(doc: Doc | Doc[]): void;
/**
* Insert an array of documents in the index
* If a constraint is violated, the changes should be rolled back and an error thrown
*
*/
private insertMultipleDocs;
/**
* Remove a document from the index
* If an array is passed, we remove all its elements
* The remove operation is safe with regards to the 'unique' constraint
* O(log(n))
*/
remove(doc: Doc | Doc[]): void;
/**
* Update a document in the index
* If a constraint is violated, changes are rolled back and an error thrown
* Naive implementation, still in O(log(n))
*/
update(oldDoc: Doc | Array>, newDoc?: Doc): void;
/**
* Update multiple documents in the index
* If a constraint is violated, the changes need to be rolled back
* and an error thrown
*/
private updateMultipleDocs;
/**
* Revert an update
*/
revertUpdate(oldDoc: Doc | Array>, newDoc?: Doc): void;
/**
* Get all documents in index whose key match value (if it is a Thing) or one of the elements of value (if it is an array of Things)
*/
getMatching(key: Key): Doc[];
getAll(): Doc[];
getBetweenBounds(query: any): Doc[];
}
type PersistenceEventCallback = (message: string) => Promise;
type PersistenceEventEmits = "readLine" | "writeLine" | "end";
declare class PersistenceEvent {
callbacks: {
readLine: Array;
writeLine: Array;
end: Array;
};
on(event: PersistenceEventEmits, cb: PersistenceEventCallback): void;
emit(event: PersistenceEventEmits, data: string): Promise;
}
interface PersistenceOptions> {
db: Datastore;
afterSerialization?: (raw: string) => string;
beforeDeserialization?: (encrypted: string) => string;
corruptAlertThreshold?: number;
model?: (new () => G) & {
new: (json: G) => G;
};
} /**
* Create a new Persistence object for database options.db
*/
/**
* Create a new Persistence object for database options.db
*/
declare class Persistence = any> {
db: Datastore;
ref: string;
corruptAlertThreshold: number;
afterSerialization: (s: string) => string;
beforeDeserialization: (s: string) => string;
autocompactionIntervalId: NodeJS.Timeout | undefined;
private _model;
protected _memoryIndexes: string[];
protected _memoryData: string[];
constructor(options: PersistenceOptions);
private persistAllIndexes;
private persistAllData;
private persistCachedDatabase;
/**
* Queue a rewrite of the datafile
*/
compactDatafile(): Promise;
/**
* Set automatic compaction every interval ms
*/
setAutocompactionInterval(interval?: number): void;
/**
* Stop autocompaction (do nothing if autocompaction was not running)
*/
stopAutocompaction(): void;
persistByAppendNewIndex(newDocs: any[]): Promise;
persistByAppendNewData(newDocs: any[]): Promise;
treatSingleLine(line: string): {
type: "index" | "doc" | "corrupt";
status: "add" | "remove";
data: any;
};
/**
* Load the database
* 1) Create all indexes
* 2) Insert all data
* This means pulling data out of the data file or creating it if it doesn't exist
*/
loadDatabase(): Promise;
init(): Promise;
readIndexes(event: PersistenceEvent): Promise;
readData(event: PersistenceEvent): Promise;
rewriteIndexes(event: PersistenceEvent): Promise;
rewriteData(event: PersistenceEvent): Promise;
appendIndex(data: string): Promise;
appendData(data: string): Promise;
forcefulUnlock(): Promise;
}
declare namespace types { }
interface EnsureIndexOptions {
fieldName: string;
unique?: boolean;
sparse?: boolean;
expireAfterSeconds?: number;
}
interface DataStoreOptions {
ref: string;
afterSerialization?(line: string): string;
beforeDeserialization?(line: string): string;
corruptAlertThreshold?: number;
timestampData?: boolean;
persistence_adapter?: typeof Persistence;
model?: (new () => G) & {
new: (json: G) => G;
};
}
interface UpdateOptions {
multi?: boolean;
upsert?: boolean;
}
declare class Datastore & {
[key: string]: any;
}> {
ref: string;
timestampData: boolean;
persistence: Persistence;
// rename to something denotes that it's an internal thing
q: Q;
indexes: {
[key: string]: Index;
};
ttlIndexes: {
[key: string]: number;
};
model: (new () => G) & {
new: (json: G) => G;
};
constructor(options: DataStoreOptions);
/**
* Load the database from the datafile, and trigger the execution of buffered commands if any
*/
loadDatabase(): Promise;
/**
* Get an array of all the data in the database
*/
getAllData(): G[];
/**
* Reset all currently defined indexes
*/
resetIndexes(): void;
/**
* Ensure an index is kept for this field. Same parameters as lib/indexes
* For now this function is synchronous, we need to test how much time it takes
* We use an async API for consistency with the rest of the code
*/
ensureIndex(options: EnsureIndexOptions): Promise<{
affectedIndex: string;
}>;
/**
* Remove an index
*/
removeIndex(fieldName: string): Promise<{
affectedIndex: string;
}>;
/**
* Add one or several document(s) to all indexes
*/
addToIndexes(doc: T | T[]): void;
/**
* Remove one or several document(s) from all indexes
*/
removeFromIndexes(doc: T | T[]): void;
/**
* Update one or several documents in all indexes
* To update multiple documents, oldDoc must be an array of { oldDoc, newDoc } pairs
* If one update violates a constraint, all changes are rolled back
*/
updateIndexes