started mongo stuff, but it's a PITA. fuck mongo
This commit is contained in:
parent
4cd36ea3fc
commit
0f1bc5dff3
937 changed files with 205043 additions and 0 deletions
494
parts/3/phonebookBackend/node_modules/sift/src/core.ts
generated
vendored
Normal file
494
parts/3/phonebookBackend/node_modules/sift/src/core.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,494 @@
|
|||
import {
|
||||
isArray,
|
||||
Key,
|
||||
Comparator,
|
||||
isVanillaObject,
|
||||
comparable,
|
||||
equals,
|
||||
coercePotentiallyNull,
|
||||
isProperty,
|
||||
} from "./utils";
|
||||
|
||||
export interface Operation<TItem> {
|
||||
readonly keep: boolean;
|
||||
readonly done: boolean;
|
||||
propop: boolean;
|
||||
reset();
|
||||
next(item: TItem, key?: Key, owner?: any, root?: boolean, leaf?: boolean);
|
||||
}
|
||||
|
||||
export type Tester = (
|
||||
item: any,
|
||||
key?: Key,
|
||||
owner?: any,
|
||||
root?: boolean,
|
||||
leaf?: boolean,
|
||||
) => boolean;
|
||||
|
||||
export interface NamedOperation {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export type OperationCreator<TItem> = (
|
||||
params: any,
|
||||
parentQuery: any,
|
||||
options: Options,
|
||||
name: string,
|
||||
) => Operation<TItem>;
|
||||
|
||||
export type BasicValueQuery<TValue> = {
|
||||
$eq?: TValue;
|
||||
$ne?: TValue;
|
||||
$lt?: TValue;
|
||||
$gt?: TValue;
|
||||
$lte?: TValue;
|
||||
$gte?: TValue;
|
||||
$in?: TValue[];
|
||||
$nin?: TValue[];
|
||||
$all?: TValue[];
|
||||
$mod?: [number, number];
|
||||
$exists?: boolean;
|
||||
$regex?: string | RegExp;
|
||||
$size?: number;
|
||||
$where?: ((this: TValue, obj: TValue) => boolean) | string;
|
||||
$options?: "i" | "g" | "m" | "u";
|
||||
$type?: Function;
|
||||
$not?: NestedQuery<TValue>;
|
||||
$or?: NestedQuery<TValue>[];
|
||||
$nor?: NestedQuery<TValue>[];
|
||||
$and?: NestedQuery<TValue>[];
|
||||
};
|
||||
|
||||
export type ArrayValueQuery<TValue> = {
|
||||
$elemMatch?: Query<TValue>;
|
||||
} & BasicValueQuery<TValue>;
|
||||
type Unpacked<T> = T extends (infer U)[] ? U : T;
|
||||
|
||||
export type ValueQuery<TValue> =
|
||||
TValue extends Array<any>
|
||||
? ArrayValueQuery<Unpacked<TValue>>
|
||||
: BasicValueQuery<TValue>;
|
||||
|
||||
type NotObject = string | number | Date | boolean | Array<any>;
|
||||
export type ShapeQuery<TItemSchema> = TItemSchema extends NotObject
|
||||
? {}
|
||||
: { [k in keyof TItemSchema]?: TItemSchema[k] | ValueQuery<TItemSchema[k]> };
|
||||
|
||||
export type NestedQuery<TItemSchema> = ValueQuery<TItemSchema> &
|
||||
ShapeQuery<TItemSchema>;
|
||||
export type Query<TItemSchema> =
|
||||
| TItemSchema
|
||||
| RegExp
|
||||
| NestedQuery<TItemSchema>;
|
||||
|
||||
export type QueryOperators<TValue = any> = keyof ValueQuery<TValue>;
|
||||
|
||||
/**
|
||||
* Walks through each value given the context - used for nested operations. E.g:
|
||||
* { "person.address": { $eq: "blarg" }}
|
||||
*/
|
||||
|
||||
const walkKeyPathValues = (
|
||||
item: any,
|
||||
keyPath: Key[],
|
||||
next: Tester,
|
||||
depth: number,
|
||||
key: Key,
|
||||
owner: any,
|
||||
) => {
|
||||
const currentKey = keyPath[depth];
|
||||
|
||||
// if array, then try matching. Might fall through for cases like:
|
||||
// { $eq: [1, 2, 3] }, [ 1, 2, 3 ].
|
||||
if (
|
||||
isArray(item) &&
|
||||
isNaN(Number(currentKey)) &&
|
||||
!isProperty(item, currentKey)
|
||||
) {
|
||||
for (let i = 0, { length } = item; i < length; i++) {
|
||||
// if FALSE is returned, then terminate walker. For operations, this simply
|
||||
// means that the search critera was met.
|
||||
if (!walkKeyPathValues(item[i], keyPath, next, depth, i, item)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (depth === keyPath.length || item == null) {
|
||||
return next(item, key, owner, depth === 0, depth === keyPath.length);
|
||||
}
|
||||
|
||||
return walkKeyPathValues(
|
||||
item[currentKey],
|
||||
keyPath,
|
||||
next,
|
||||
depth + 1,
|
||||
currentKey,
|
||||
item,
|
||||
);
|
||||
};
|
||||
|
||||
export abstract class BaseOperation<TParams, TItem = any>
|
||||
implements Operation<TItem>
|
||||
{
|
||||
keep: boolean;
|
||||
done: boolean;
|
||||
abstract propop: boolean;
|
||||
constructor(
|
||||
readonly params: TParams,
|
||||
readonly owneryQuery: any,
|
||||
readonly options: Options,
|
||||
readonly name?: string,
|
||||
) {
|
||||
this.init();
|
||||
}
|
||||
protected init() {}
|
||||
reset() {
|
||||
this.done = false;
|
||||
this.keep = false;
|
||||
}
|
||||
abstract next(
|
||||
item: any,
|
||||
key: Key,
|
||||
parent: any,
|
||||
root: boolean,
|
||||
leaf?: boolean,
|
||||
);
|
||||
}
|
||||
|
||||
abstract class GroupOperation extends BaseOperation<any> {
|
||||
keep: boolean;
|
||||
done: boolean;
|
||||
|
||||
constructor(
|
||||
params: any,
|
||||
owneryQuery: any,
|
||||
options: Options,
|
||||
public readonly children: Operation<any>[],
|
||||
) {
|
||||
super(params, owneryQuery, options);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
reset() {
|
||||
this.keep = false;
|
||||
this.done = false;
|
||||
for (let i = 0, { length } = this.children; i < length; i++) {
|
||||
this.children[i].reset();
|
||||
}
|
||||
}
|
||||
|
||||
abstract next(item: any, key: Key, owner: any, root: boolean);
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
protected childrenNext(
|
||||
item: any,
|
||||
key: Key,
|
||||
owner: any,
|
||||
root: boolean,
|
||||
leaf?: boolean,
|
||||
) {
|
||||
let done = true;
|
||||
let keep = true;
|
||||
for (let i = 0, { length } = this.children; i < length; i++) {
|
||||
const childOperation = this.children[i];
|
||||
if (!childOperation.done) {
|
||||
childOperation.next(item, key, owner, root, leaf);
|
||||
}
|
||||
if (!childOperation.keep) {
|
||||
keep = false;
|
||||
}
|
||||
if (childOperation.done) {
|
||||
if (!childOperation.keep) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
done = false;
|
||||
}
|
||||
}
|
||||
this.done = done;
|
||||
this.keep = keep;
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class NamedGroupOperation
|
||||
extends GroupOperation
|
||||
implements NamedOperation
|
||||
{
|
||||
abstract propop: boolean;
|
||||
constructor(
|
||||
params: any,
|
||||
owneryQuery: any,
|
||||
options: Options,
|
||||
children: Operation<any>[],
|
||||
readonly name: string,
|
||||
) {
|
||||
super(params, owneryQuery, options, children);
|
||||
}
|
||||
}
|
||||
|
||||
export class QueryOperation<TItem> extends GroupOperation {
|
||||
readonly propop = true;
|
||||
/**
|
||||
*/
|
||||
|
||||
next(item: TItem, key: Key, parent: any, root: boolean) {
|
||||
this.childrenNext(item, key, parent, root);
|
||||
}
|
||||
}
|
||||
|
||||
export class NestedOperation extends GroupOperation {
|
||||
readonly propop = true;
|
||||
constructor(
|
||||
readonly keyPath: Key[],
|
||||
params: any,
|
||||
owneryQuery: any,
|
||||
options: Options,
|
||||
children: Operation<any>[],
|
||||
) {
|
||||
super(params, owneryQuery, options, children);
|
||||
}
|
||||
/**
|
||||
*/
|
||||
|
||||
next(item: any, key: Key, parent: any) {
|
||||
walkKeyPathValues(
|
||||
item,
|
||||
this.keyPath,
|
||||
this._nextNestedValue,
|
||||
0,
|
||||
key,
|
||||
parent,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
private _nextNestedValue = (
|
||||
value: any,
|
||||
key: Key,
|
||||
owner: any,
|
||||
root: boolean,
|
||||
leaf: boolean,
|
||||
) => {
|
||||
this.childrenNext(value, key, owner, root, leaf);
|
||||
return !this.done;
|
||||
};
|
||||
}
|
||||
|
||||
export const createTester = (a, compare: Comparator) => {
|
||||
if (a instanceof Function) {
|
||||
return a;
|
||||
}
|
||||
if (a instanceof RegExp) {
|
||||
return (b) => {
|
||||
const result = typeof b === "string" && a.test(b);
|
||||
a.lastIndex = 0;
|
||||
return result;
|
||||
};
|
||||
}
|
||||
const comparableA = comparable(a);
|
||||
return (b) => compare(comparableA, comparable(b));
|
||||
};
|
||||
|
||||
export class EqualsOperation<TParam> extends BaseOperation<TParam> {
|
||||
readonly propop = true;
|
||||
private _test: Tester;
|
||||
init() {
|
||||
this._test = createTester(this.params, this.options.compare);
|
||||
}
|
||||
next(item, key: Key, parent: any) {
|
||||
if (!Array.isArray(parent) || parent.hasOwnProperty(key)) {
|
||||
if (this._test(item, key, parent)) {
|
||||
this.done = true;
|
||||
this.keep = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const createEqualsOperation = (
|
||||
params: any,
|
||||
owneryQuery: any,
|
||||
options: Options,
|
||||
) => new EqualsOperation(params, owneryQuery, options);
|
||||
|
||||
export const numericalOperationCreator =
|
||||
(createNumericalOperation: OperationCreator<any>) =>
|
||||
(params: any, owneryQuery: any, options: Options, name: string) => {
|
||||
return createNumericalOperation(params, owneryQuery, options, name);
|
||||
};
|
||||
|
||||
export const numericalOperation = (createTester: (value: any) => Tester) =>
|
||||
numericalOperationCreator(
|
||||
(params: any, owneryQuery: Query<any>, options: Options, name: string) => {
|
||||
const typeofParams = typeof comparable(params);
|
||||
const test = createTester(params);
|
||||
return new EqualsOperation(
|
||||
(b) => {
|
||||
const actualValue = coercePotentiallyNull(b);
|
||||
return (
|
||||
typeof comparable(actualValue) === typeofParams && test(actualValue)
|
||||
);
|
||||
},
|
||||
owneryQuery,
|
||||
options,
|
||||
name,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export type Options = {
|
||||
operations: {
|
||||
[identifier: string]: OperationCreator<any>;
|
||||
};
|
||||
compare: (a, b) => boolean;
|
||||
};
|
||||
|
||||
const createNamedOperation = (
|
||||
name: string,
|
||||
params: any,
|
||||
parentQuery: any,
|
||||
options: Options,
|
||||
) => {
|
||||
const operationCreator = options.operations[name];
|
||||
if (!operationCreator) {
|
||||
throwUnsupportedOperation(name);
|
||||
}
|
||||
return operationCreator(params, parentQuery, options, name);
|
||||
};
|
||||
|
||||
const throwUnsupportedOperation = (name: string) => {
|
||||
throw new Error(`Unsupported operation: ${name}`);
|
||||
};
|
||||
|
||||
export const containsOperation = (query: any, options: Options) => {
|
||||
for (const key in query) {
|
||||
if (options.operations.hasOwnProperty(key) || key.charAt(0) === "$")
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const createNestedOperation = (
|
||||
keyPath: Key[],
|
||||
nestedQuery: any,
|
||||
parentKey: string,
|
||||
owneryQuery: any,
|
||||
options: Options,
|
||||
) => {
|
||||
if (containsOperation(nestedQuery, options)) {
|
||||
const [selfOperations, nestedOperations] = createQueryOperations(
|
||||
nestedQuery,
|
||||
parentKey,
|
||||
options,
|
||||
);
|
||||
if (nestedOperations.length) {
|
||||
throw new Error(
|
||||
`Property queries must contain only operations, or exact objects.`,
|
||||
);
|
||||
}
|
||||
return new NestedOperation(
|
||||
keyPath,
|
||||
nestedQuery,
|
||||
owneryQuery,
|
||||
options,
|
||||
selfOperations,
|
||||
);
|
||||
}
|
||||
return new NestedOperation(keyPath, nestedQuery, owneryQuery, options, [
|
||||
new EqualsOperation(nestedQuery, owneryQuery, options),
|
||||
]);
|
||||
};
|
||||
|
||||
export const createQueryOperation = <TItem, TSchema = TItem>(
|
||||
query: Query<TSchema>,
|
||||
owneryQuery: any = null,
|
||||
{ compare, operations }: Partial<Options> = {},
|
||||
): QueryOperation<TItem> => {
|
||||
const options = {
|
||||
compare: compare || equals,
|
||||
operations: Object.assign({}, operations || {}),
|
||||
};
|
||||
|
||||
const [selfOperations, nestedOperations] = createQueryOperations(
|
||||
query,
|
||||
null,
|
||||
options,
|
||||
);
|
||||
|
||||
const ops = [];
|
||||
|
||||
if (selfOperations.length) {
|
||||
ops.push(
|
||||
new NestedOperation([], query, owneryQuery, options, selfOperations),
|
||||
);
|
||||
}
|
||||
|
||||
ops.push(...nestedOperations);
|
||||
|
||||
if (ops.length === 1) {
|
||||
return ops[0];
|
||||
}
|
||||
return new QueryOperation(query, owneryQuery, options, ops);
|
||||
};
|
||||
|
||||
const createQueryOperations = (
|
||||
query: any,
|
||||
parentKey: string,
|
||||
options: Options,
|
||||
) => {
|
||||
const selfOperations = [];
|
||||
const nestedOperations = [];
|
||||
if (!isVanillaObject(query)) {
|
||||
selfOperations.push(new EqualsOperation(query, query, options));
|
||||
return [selfOperations, nestedOperations];
|
||||
}
|
||||
for (const key in query) {
|
||||
if (options.operations.hasOwnProperty(key)) {
|
||||
const op = createNamedOperation(key, query[key], query, options);
|
||||
|
||||
if (op) {
|
||||
if (!op.propop && parentKey && !options.operations[parentKey]) {
|
||||
throw new Error(
|
||||
`Malformed query. ${key} cannot be matched against property.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// probably just a flag for another operation (like $options)
|
||||
if (op != null) {
|
||||
selfOperations.push(op);
|
||||
}
|
||||
} else if (key.charAt(0) === "$") {
|
||||
throwUnsupportedOperation(key);
|
||||
} else {
|
||||
nestedOperations.push(
|
||||
createNestedOperation(key.split("."), query[key], key, query, options),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return [selfOperations, nestedOperations];
|
||||
};
|
||||
|
||||
export const createOperationTester =
|
||||
<TItem>(operation: Operation<TItem>) =>
|
||||
(item: TItem, key?: Key, owner?: any) => {
|
||||
operation.reset();
|
||||
operation.next(item, key, owner);
|
||||
return operation.keep;
|
||||
};
|
||||
|
||||
export const createQueryTester = <TItem, TSchema = TItem>(
|
||||
query: Query<TSchema>,
|
||||
options: Partial<Options> = {},
|
||||
) => {
|
||||
return createOperationTester(
|
||||
createQueryOperation<TItem, TSchema>(query, null, options),
|
||||
);
|
||||
};
|
||||
54
parts/3/phonebookBackend/node_modules/sift/src/index.ts
generated
vendored
Normal file
54
parts/3/phonebookBackend/node_modules/sift/src/index.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import * as defaultOperations from "./operations";
|
||||
import {
|
||||
Query,
|
||||
QueryOperators,
|
||||
BasicValueQuery,
|
||||
ArrayValueQuery,
|
||||
ValueQuery,
|
||||
NestedQuery,
|
||||
ShapeQuery,
|
||||
Options,
|
||||
createQueryTester,
|
||||
EqualsOperation,
|
||||
createQueryOperation,
|
||||
createEqualsOperation,
|
||||
createOperationTester,
|
||||
} from "./core";
|
||||
|
||||
const createDefaultQueryOperation = <TItem, TSchema extends TItem = TItem>(
|
||||
query: Query<TSchema>,
|
||||
ownerQuery: any,
|
||||
{ compare, operations }: Partial<Options> = {},
|
||||
) => {
|
||||
return createQueryOperation(query, ownerQuery, {
|
||||
compare,
|
||||
operations: Object.assign({}, defaultOperations, operations || {}),
|
||||
});
|
||||
};
|
||||
|
||||
const createDefaultQueryTester = <TItem, TSchema extends TItem = TItem>(
|
||||
query: Query<TSchema>,
|
||||
options: Partial<Options> = {},
|
||||
) => {
|
||||
const op = createDefaultQueryOperation(query, null, options);
|
||||
return createOperationTester(op);
|
||||
};
|
||||
|
||||
export {
|
||||
Query,
|
||||
QueryOperators,
|
||||
BasicValueQuery,
|
||||
ArrayValueQuery,
|
||||
ValueQuery,
|
||||
NestedQuery,
|
||||
ShapeQuery,
|
||||
EqualsOperation,
|
||||
createQueryTester,
|
||||
createOperationTester,
|
||||
createDefaultQueryOperation,
|
||||
createEqualsOperation,
|
||||
createQueryOperation,
|
||||
};
|
||||
export * from "./operations";
|
||||
|
||||
export default createDefaultQueryTester;
|
||||
422
parts/3/phonebookBackend/node_modules/sift/src/operations.ts
generated
vendored
Normal file
422
parts/3/phonebookBackend/node_modules/sift/src/operations.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,422 @@
|
|||
import {
|
||||
BaseOperation,
|
||||
EqualsOperation,
|
||||
Options,
|
||||
createTester,
|
||||
Tester,
|
||||
createQueryOperation,
|
||||
QueryOperation,
|
||||
Operation,
|
||||
Query,
|
||||
NamedGroupOperation,
|
||||
numericalOperation,
|
||||
containsOperation,
|
||||
} from "./core";
|
||||
import { Key, comparable, isFunction, isArray } from "./utils";
|
||||
|
||||
class $Ne extends BaseOperation<any> {
|
||||
readonly propop = true;
|
||||
private _test: Tester;
|
||||
init() {
|
||||
this._test = createTester(this.params, this.options.compare);
|
||||
}
|
||||
reset() {
|
||||
super.reset();
|
||||
this.keep = true;
|
||||
}
|
||||
next(item: any) {
|
||||
if (this._test(item)) {
|
||||
this.done = true;
|
||||
this.keep = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// https://docs.mongodb.com/manual/reference/operator/query/elemMatch/
|
||||
class $ElemMatch extends BaseOperation<Query<any>> {
|
||||
readonly propop = true;
|
||||
private _queryOperation: QueryOperation<any>;
|
||||
init() {
|
||||
if (!this.params || typeof this.params !== "object") {
|
||||
throw new Error(`Malformed query. $elemMatch must by an object.`);
|
||||
}
|
||||
this._queryOperation = createQueryOperation(
|
||||
this.params,
|
||||
this.owneryQuery,
|
||||
this.options,
|
||||
);
|
||||
}
|
||||
reset() {
|
||||
super.reset();
|
||||
this._queryOperation.reset();
|
||||
}
|
||||
next(item: any) {
|
||||
if (isArray(item)) {
|
||||
for (let i = 0, { length } = item; i < length; i++) {
|
||||
// reset query operation since item being tested needs to pass _all_ query
|
||||
// operations for it to be a success
|
||||
this._queryOperation.reset();
|
||||
|
||||
const child = item[i];
|
||||
this._queryOperation.next(child, i, item, false);
|
||||
this.keep = this.keep || this._queryOperation.keep;
|
||||
}
|
||||
this.done = true;
|
||||
} else {
|
||||
this.done = false;
|
||||
this.keep = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class $Not extends BaseOperation<Query<any>> {
|
||||
readonly propop = true;
|
||||
private _queryOperation: QueryOperation<any>;
|
||||
init() {
|
||||
this._queryOperation = createQueryOperation(
|
||||
this.params,
|
||||
this.owneryQuery,
|
||||
this.options,
|
||||
);
|
||||
}
|
||||
reset() {
|
||||
super.reset();
|
||||
this._queryOperation.reset();
|
||||
}
|
||||
next(item: any, key: Key, owner: any, root: boolean) {
|
||||
this._queryOperation.next(item, key, owner, root);
|
||||
this.done = this._queryOperation.done;
|
||||
this.keep = !this._queryOperation.keep;
|
||||
}
|
||||
}
|
||||
|
||||
export class $Size extends BaseOperation<any> {
|
||||
readonly propop = true;
|
||||
init() {}
|
||||
next(item) {
|
||||
if (isArray(item) && item.length === this.params) {
|
||||
this.done = true;
|
||||
this.keep = true;
|
||||
}
|
||||
// if (parent && parent.length === this.params) {
|
||||
// this.done = true;
|
||||
// this.keep = true;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
const assertGroupNotEmpty = (values: any[]) => {
|
||||
if (values.length === 0) {
|
||||
throw new Error(`$and/$or/$nor must be a nonempty array`);
|
||||
}
|
||||
};
|
||||
|
||||
class $Or extends BaseOperation<any> {
|
||||
readonly propop = false;
|
||||
private _ops: Operation<any>[];
|
||||
init() {
|
||||
assertGroupNotEmpty(this.params);
|
||||
this._ops = this.params.map((op) =>
|
||||
createQueryOperation(op, null, this.options),
|
||||
);
|
||||
}
|
||||
reset() {
|
||||
this.done = false;
|
||||
this.keep = false;
|
||||
for (let i = 0, { length } = this._ops; i < length; i++) {
|
||||
this._ops[i].reset();
|
||||
}
|
||||
}
|
||||
next(item: any, key: Key, owner: any) {
|
||||
let done = false;
|
||||
let success = false;
|
||||
for (let i = 0, { length } = this._ops; i < length; i++) {
|
||||
const op = this._ops[i];
|
||||
op.next(item, key, owner);
|
||||
if (op.keep) {
|
||||
done = true;
|
||||
success = op.keep;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.keep = success;
|
||||
this.done = done;
|
||||
}
|
||||
}
|
||||
|
||||
class $Nor extends $Or {
|
||||
readonly propop = false;
|
||||
next(item: any, key: Key, owner: any) {
|
||||
super.next(item, key, owner);
|
||||
this.keep = !this.keep;
|
||||
}
|
||||
}
|
||||
|
||||
class $In extends BaseOperation<any> {
|
||||
readonly propop = true;
|
||||
private _testers: Tester[];
|
||||
init() {
|
||||
const params = Array.isArray(this.params) ? this.params : [this.params];
|
||||
this._testers = params.map((value) => {
|
||||
if (containsOperation(value, this.options)) {
|
||||
throw new Error(`cannot nest $ under ${this.name.toLowerCase()}`);
|
||||
}
|
||||
return createTester(value, this.options.compare);
|
||||
});
|
||||
}
|
||||
next(item: any, key: Key, owner: any) {
|
||||
let done = false;
|
||||
let success = false;
|
||||
for (let i = 0, { length } = this._testers; i < length; i++) {
|
||||
const test = this._testers[i];
|
||||
if (test(item)) {
|
||||
done = true;
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.keep = success;
|
||||
this.done = done;
|
||||
}
|
||||
}
|
||||
|
||||
class $Nin extends BaseOperation<any> {
|
||||
readonly propop = true;
|
||||
private _in: $In;
|
||||
constructor(params: any, ownerQuery: any, options: Options, name: string) {
|
||||
super(params, ownerQuery, options, name);
|
||||
this._in = new $In(params, ownerQuery, options, name);
|
||||
}
|
||||
next(item: any, key: Key, owner: any, root: boolean) {
|
||||
this._in.next(item, key, owner);
|
||||
|
||||
if (isArray(owner) && !root) {
|
||||
if (this._in.keep) {
|
||||
this.keep = false;
|
||||
this.done = true;
|
||||
} else if (key == owner.length - 1) {
|
||||
this.keep = true;
|
||||
this.done = true;
|
||||
}
|
||||
} else {
|
||||
this.keep = !this._in.keep;
|
||||
this.done = true;
|
||||
}
|
||||
}
|
||||
reset() {
|
||||
super.reset();
|
||||
this._in.reset();
|
||||
}
|
||||
}
|
||||
|
||||
class $Exists extends BaseOperation<boolean> {
|
||||
readonly propop = true;
|
||||
next(item: any, key: Key, owner: any, root: boolean, leaf?: boolean) {
|
||||
if (!leaf) {
|
||||
this.done = true;
|
||||
this.keep = !this.params;
|
||||
} else if (owner.hasOwnProperty(key) === this.params) {
|
||||
this.done = true;
|
||||
this.keep = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class $And extends NamedGroupOperation {
|
||||
readonly propop = false;
|
||||
constructor(
|
||||
params: Query<any>[],
|
||||
owneryQuery: Query<any>,
|
||||
options: Options,
|
||||
name: string,
|
||||
) {
|
||||
super(
|
||||
params,
|
||||
owneryQuery,
|
||||
options,
|
||||
params.map((query) => createQueryOperation(query, owneryQuery, options)),
|
||||
name,
|
||||
);
|
||||
|
||||
assertGroupNotEmpty(params);
|
||||
}
|
||||
next(item: any, key: Key, owner: any, root: boolean) {
|
||||
this.childrenNext(item, key, owner, root);
|
||||
}
|
||||
}
|
||||
|
||||
class $All extends NamedGroupOperation {
|
||||
readonly propop = true;
|
||||
constructor(
|
||||
params: Query<any>[],
|
||||
owneryQuery: Query<any>,
|
||||
options: Options,
|
||||
name: string,
|
||||
) {
|
||||
super(
|
||||
params,
|
||||
owneryQuery,
|
||||
options,
|
||||
params.map((query) => createQueryOperation(query, owneryQuery, options)),
|
||||
name,
|
||||
);
|
||||
}
|
||||
next(item: any, key: Key, owner: any, root: boolean) {
|
||||
this.childrenNext(item, key, owner, root);
|
||||
}
|
||||
}
|
||||
|
||||
export const $eq = (params: any, owneryQuery: Query<any>, options: Options) =>
|
||||
new EqualsOperation(params, owneryQuery, options);
|
||||
export const $ne = (
|
||||
params: any,
|
||||
owneryQuery: Query<any>,
|
||||
options: Options,
|
||||
name: string,
|
||||
) => new $Ne(params, owneryQuery, options, name);
|
||||
export const $or = (
|
||||
params: Query<any>[],
|
||||
owneryQuery: Query<any>,
|
||||
options: Options,
|
||||
name: string,
|
||||
) => new $Or(params, owneryQuery, options, name);
|
||||
export const $nor = (
|
||||
params: Query<any>[],
|
||||
owneryQuery: Query<any>,
|
||||
options: Options,
|
||||
name: string,
|
||||
) => new $Nor(params, owneryQuery, options, name);
|
||||
export const $elemMatch = (
|
||||
params: any,
|
||||
owneryQuery: Query<any>,
|
||||
options: Options,
|
||||
name: string,
|
||||
) => new $ElemMatch(params, owneryQuery, options, name);
|
||||
export const $nin = (
|
||||
params: any,
|
||||
owneryQuery: Query<any>,
|
||||
options: Options,
|
||||
name: string,
|
||||
) => new $Nin(params, owneryQuery, options, name);
|
||||
export const $in = (
|
||||
params: any,
|
||||
owneryQuery: Query<any>,
|
||||
options: Options,
|
||||
name: string,
|
||||
) => {
|
||||
return new $In(params, owneryQuery, options, name);
|
||||
};
|
||||
|
||||
export const $lt = numericalOperation((params) => (b) => {
|
||||
return b != null && b < params;
|
||||
});
|
||||
export const $lte = numericalOperation((params) => (b) => {
|
||||
return b === params || b <= params;
|
||||
});
|
||||
export const $gt = numericalOperation((params) => (b) => {
|
||||
return b != null && b > params;
|
||||
});
|
||||
export const $gte = numericalOperation((params) => (b) => {
|
||||
return b === params || b >= params;
|
||||
});
|
||||
export const $mod = (
|
||||
[mod, equalsValue]: number[],
|
||||
owneryQuery: Query<any>,
|
||||
options: Options,
|
||||
) =>
|
||||
new EqualsOperation(
|
||||
(b) => comparable(b) % mod === equalsValue,
|
||||
owneryQuery,
|
||||
options,
|
||||
);
|
||||
export const $exists = (
|
||||
params: boolean,
|
||||
owneryQuery: Query<any>,
|
||||
options: Options,
|
||||
name: string,
|
||||
) => new $Exists(params, owneryQuery, options, name);
|
||||
export const $regex = (
|
||||
pattern: string,
|
||||
owneryQuery: Query<any>,
|
||||
options: Options,
|
||||
) =>
|
||||
new EqualsOperation(
|
||||
new RegExp(pattern, owneryQuery.$options),
|
||||
owneryQuery,
|
||||
options,
|
||||
);
|
||||
export const $not = (
|
||||
params: any,
|
||||
owneryQuery: Query<any>,
|
||||
options: Options,
|
||||
name: string,
|
||||
) => new $Not(params, owneryQuery, options, name);
|
||||
|
||||
const typeAliases = {
|
||||
number: (v) => typeof v === "number",
|
||||
string: (v) => typeof v === "string",
|
||||
bool: (v) => typeof v === "boolean",
|
||||
array: (v) => Array.isArray(v),
|
||||
null: (v) => v === null,
|
||||
timestamp: (v) => v instanceof Date,
|
||||
};
|
||||
|
||||
export const $type = (
|
||||
clazz: Function | string,
|
||||
owneryQuery: Query<any>,
|
||||
options: Options,
|
||||
) =>
|
||||
new EqualsOperation(
|
||||
(b) => {
|
||||
if (typeof clazz === "string") {
|
||||
if (!typeAliases[clazz]) {
|
||||
throw new Error(`Type alias does not exist`);
|
||||
}
|
||||
|
||||
return typeAliases[clazz](b);
|
||||
}
|
||||
|
||||
return b != null ? b instanceof clazz || b.constructor === clazz : false;
|
||||
},
|
||||
owneryQuery,
|
||||
options,
|
||||
);
|
||||
export const $and = (
|
||||
params: Query<any>[],
|
||||
ownerQuery: Query<any>,
|
||||
options: Options,
|
||||
name: string,
|
||||
) => new $And(params, ownerQuery, options, name);
|
||||
|
||||
export const $all = (
|
||||
params: Query<any>[],
|
||||
ownerQuery: Query<any>,
|
||||
options: Options,
|
||||
name: string,
|
||||
) => new $All(params, ownerQuery, options, name);
|
||||
export const $size = (
|
||||
params: number,
|
||||
ownerQuery: Query<any>,
|
||||
options: Options,
|
||||
) => new $Size(params, ownerQuery, options, "$size");
|
||||
export const $options = () => null;
|
||||
export const $where = (
|
||||
params: string | Function,
|
||||
ownerQuery: Query<any>,
|
||||
options: Options,
|
||||
) => {
|
||||
let test;
|
||||
|
||||
if (isFunction(params)) {
|
||||
test = params;
|
||||
} else if (!process.env.CSP_ENABLED) {
|
||||
test = new Function("obj", "return " + params);
|
||||
} else {
|
||||
throw new Error(
|
||||
`In CSP mode, sift does not support strings in "$where" condition`,
|
||||
);
|
||||
}
|
||||
|
||||
return new EqualsOperation((b) => test.bind(b)(b), ownerQuery, options);
|
||||
};
|
||||
74
parts/3/phonebookBackend/node_modules/sift/src/utils.ts
generated
vendored
Normal file
74
parts/3/phonebookBackend/node_modules/sift/src/utils.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
export type Key = string | number;
|
||||
export type Comparator = (a, b) => boolean;
|
||||
export const typeChecker = <TType>(type) => {
|
||||
const typeString = "[object " + type + "]";
|
||||
return function (value): value is TType {
|
||||
return getClassName(value) === typeString;
|
||||
};
|
||||
};
|
||||
|
||||
const getClassName = (value) => Object.prototype.toString.call(value);
|
||||
|
||||
export const comparable = (value: any) => {
|
||||
if (value instanceof Date) {
|
||||
return value.getTime();
|
||||
} else if (isArray(value)) {
|
||||
return value.map(comparable);
|
||||
} else if (value && typeof value.toJSON === "function") {
|
||||
return value.toJSON();
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
export const coercePotentiallyNull = (value: any) =>
|
||||
value == null ? null : value;
|
||||
|
||||
export const isArray = typeChecker<Array<any>>("Array");
|
||||
export const isObject = typeChecker<Object>("Object");
|
||||
export const isFunction = typeChecker<Function>("Function");
|
||||
export const isProperty = (item: any, key: any) => {
|
||||
return item.hasOwnProperty(key) && !isFunction(item[key]);
|
||||
};
|
||||
export const isVanillaObject = (value) => {
|
||||
return (
|
||||
value &&
|
||||
(value.constructor === Object ||
|
||||
value.constructor === Array ||
|
||||
value.constructor.toString() === "function Object() { [native code] }" ||
|
||||
value.constructor.toString() === "function Array() { [native code] }") &&
|
||||
!value.toJSON
|
||||
);
|
||||
};
|
||||
|
||||
export const equals = (a, b) => {
|
||||
if (a == null && a == b) {
|
||||
return true;
|
||||
}
|
||||
if (a === b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Object.prototype.toString.call(a) !== Object.prototype.toString.call(b)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isArray(a)) {
|
||||
if (a.length !== b.length) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0, { length } = a; i < length; i++) {
|
||||
if (!equals(a[i], b[i])) return false;
|
||||
}
|
||||
return true;
|
||||
} else if (isObject(a)) {
|
||||
if (Object.keys(a).length !== Object.keys(b).length) {
|
||||
return false;
|
||||
}
|
||||
for (const key in a) {
|
||||
if (!equals(a[key], b[key])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue