Skip to content

Commit

Permalink
fix crcn#243
Browse files Browse the repository at this point in the history
  • Loading branch information
crcn committed Feb 15, 2022
1 parent b418188 commit 3d1bf29
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 55 deletions.
65 changes: 33 additions & 32 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@ export interface Operation<TItem> {
readonly done: boolean;
propop: boolean;
reset();
next(item: TItem, key?: Key, owner?: any);
next(item: TItem, key?: Key, owner?: any, root?: boolean);
}

export type Tester = (item: any, key?: Key, owner?: any) => boolean;
export type Tester = (
item: any,
key?: Key,
owner?: any,
root?: boolean
) => boolean;

export interface NamedOperation {
name: string;
Expand Down Expand Up @@ -100,7 +105,7 @@ const walkKeyPathValues = (
}

if (depth === keyPath.length || item == null) {
return next(item, key, owner);
return next(item, key, owner, depth === 0);
}

return walkKeyPathValues(
Expand All @@ -113,14 +118,16 @@ const walkKeyPathValues = (
);
};

abstract class BaseOperation<TParams, TItem = any> implements Operation<TItem> {
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 options: Options,
readonly name?: string
) {
this.init();
}
Expand All @@ -129,21 +136,7 @@ abstract class BaseOperation<TParams, TItem = any> implements Operation<TItem> {
this.done = false;
this.keep = false;
}
abstract next(item: any, key: Key, parent: any);
}

export abstract class NamedBaseOperation<TParams, TItem = any>
extends BaseOperation<TParams, TItem>
implements NamedOperation {
abstract propop: boolean;
constructor(
params: TParams,
owneryQuery: any,
options: Options,
readonly name: string
) {
super(params, owneryQuery, options);
}
abstract next(item: any, key: Key, parent: any, root: boolean);
}

abstract class GroupOperation extends BaseOperation<any> {
Expand All @@ -170,17 +163,19 @@ abstract class GroupOperation extends BaseOperation<any> {
}
}

abstract next(item: any, key: Key, owner: any);
abstract next(item: any, key: Key, owner: any, root: boolean);

/**
*/

protected childrenNext(item: any, key: Key, owner: any) {
protected childrenNext(item: any, key: Key, owner: any, root: boolean) {
let done = true;
let keep = true;
for (let i = 0, { length } = this.children; i < length; i++) {
const childOperation = this.children[i];
childOperation.next(item, key, owner);
if (!childOperation.done) {
childOperation.next(item, key, owner, root);
}
if (!childOperation.keep) {
keep = false;
}
Expand Down Expand Up @@ -216,8 +211,8 @@ export class QueryOperation<TItem> extends GroupOperation {
/**
*/

next(item: TItem, key: Key, parent: any) {
this.childrenNext(item, key, parent);
next(item: TItem, key: Key, parent: any, root: boolean) {
this.childrenNext(item, key, parent, root);
}
}

Expand Down Expand Up @@ -249,8 +244,13 @@ export class NestedOperation extends GroupOperation {
/**
*/

private _nextNestedValue = (value: any, key: Key, owner: any) => {
this.childrenNext(value, key, owner);
private _nextNestedValue = (
value: any,
key: Key,
owner: any,
root: boolean
) => {
this.childrenNext(value, key, owner, root);
return !this.done;
};
}
Expand Down Expand Up @@ -290,7 +290,7 @@ export const createEqualsOperation = (
params: any,
owneryQuery: any,
options: Options
) => new EqualsOperation(params, owneryQuery, options);
) => new EqualsOperation(params, owneryQuery, options, "$eq");

export class NopeOperation<TParam> extends BaseOperation<TParam> {
readonly propop = true;
Expand All @@ -304,23 +304,24 @@ export const numericalOperationCreator = (
createNumericalOperation: OperationCreator<any>
) => (params: any, owneryQuery: any, options: Options, name: string) => {
if (params == null) {
return new NopeOperation(params, owneryQuery, options);
return new NopeOperation(params, owneryQuery, options, name);
}

return createNumericalOperation(params, owneryQuery, options, name);
};

export const numericalOperation = (createTester: (any) => Tester) =>
numericalOperationCreator(
(params: any, owneryQuery: Query<any>, options: Options) => {
(params: any, owneryQuery: Query<any>, options: Options, name: string) => {
const typeofParams = typeof comparable(params);
const test = createTester(params);
return new EqualsOperation(
b => {
return typeof comparable(b) === typeofParams && test(b);
},
owneryQuery,
options
options,
name
);
}
);
Expand Down Expand Up @@ -427,7 +428,7 @@ const createQueryOperations = (
const selfOperations = [];
const nestedOperations = [];
if (!isVanillaObject(query)) {
selfOperations.push(new EqualsOperation(query, query, options));
selfOperations.push(new EqualsOperation(query, query, options, "$eq"));
return [selfOperations, nestedOperations];
}
for (const key in query) {
Expand Down
68 changes: 45 additions & 23 deletions src/operations.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
NamedBaseOperation,
BaseOperation,
EqualsOperation,
Options,
createTester,
Expand All @@ -15,7 +15,7 @@ import {
} from "./core";
import { Key, comparable, isFunction, isArray } from "./utils";

class $Ne extends NamedBaseOperation<any> {
class $Ne extends BaseOperation<any> {
readonly propop = true;
private _test: Tester;
init() {
Expand All @@ -33,7 +33,7 @@ class $Ne extends NamedBaseOperation<any> {
}
}
// https://docs.mongodb.com/manual/reference/operator/query/elemMatch/
class $ElemMatch extends NamedBaseOperation<Query<any>> {
class $ElemMatch extends BaseOperation<Query<any>> {
readonly propop = true;
private _queryOperation: QueryOperation<any>;
init() {
Expand All @@ -58,7 +58,7 @@ class $ElemMatch extends NamedBaseOperation<Query<any>> {
this._queryOperation.reset();

const child = item[i];
this._queryOperation.next(child, i, item);
this._queryOperation.next(child, i, item, false);
this.keep = this.keep || this._queryOperation.keep;
}
this.done = true;
Expand All @@ -69,7 +69,7 @@ class $ElemMatch extends NamedBaseOperation<Query<any>> {
}
}

class $Not extends NamedBaseOperation<Query<any>> {
class $Not extends BaseOperation<Query<any>> {
readonly propop = true;
private _queryOperation: QueryOperation<any>;
init() {
Expand All @@ -80,16 +80,17 @@ class $Not extends NamedBaseOperation<Query<any>> {
);
}
reset() {
super.reset();
this._queryOperation.reset();
}
next(item: any, key: Key, owner: any) {
this._queryOperation.next(item, key, owner);
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 NamedBaseOperation<any> {
export class $Size extends BaseOperation<any> {
readonly propop = true;
init() {}
next(item) {
Expand All @@ -110,7 +111,7 @@ const assertGroupNotEmpty = (values: any[]) => {
}
};

class $Or extends NamedBaseOperation<any> {
class $Or extends BaseOperation<any> {
readonly propop = false;
private _ops: Operation<any>[];
init() {
Expand Down Expand Up @@ -152,15 +153,13 @@ class $Nor extends $Or {
}
}

class $In extends NamedBaseOperation<any> {
class $In extends BaseOperation<any> {
readonly propop = true;
private _testers: Tester[];
init() {
this._testers = this.params.map(value => {
if (containsOperation(value, this.options)) {
throw new Error(
`cannot nest $ under ${this.constructor.name.toLowerCase()}`
);
throw new Error(`cannot nest $ under ${this.name.toLowerCase()}`);
}
return createTester(value, this.options.compare);
});
Expand All @@ -182,15 +181,36 @@ class $In extends NamedBaseOperation<any> {
}
}

class $Nin extends $In {
class $Nin extends BaseOperation<any> {
readonly propop = true;
next(item: any, key: Key, owner: any) {
super.next(item, key, owner);
this.keep = !this.keep;
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 NamedBaseOperation<boolean> {
class $Exists extends BaseOperation<boolean> {
readonly propop = true;
next(item: any, key: Key, owner: any) {
if (owner.hasOwnProperty(key) === this.params) {
Expand Down Expand Up @@ -218,8 +238,8 @@ class $And extends NamedGroupOperation {

assertGroupNotEmpty(params);
}
next(item: any, key: Key, owner: any) {
this.childrenNext(item, key, owner);
next(item: any, key: Key, owner: any, root: boolean) {
this.childrenNext(item, key, owner, root);
}
}

Expand All @@ -239,8 +259,8 @@ class $All extends NamedGroupOperation {
name
);
}
next(item: any, key: Key, owner: any) {
this.childrenNext(item, key, owner);
next(item: any, key: Key, owner: any, root: boolean) {
this.childrenNext(item, key, owner, root);
}
}

Expand Down Expand Up @@ -281,7 +301,9 @@ export const $in = (
owneryQuery: Query<any>,
options: Options,
name: string
) => new $In(params, owneryQuery, options, name);
) => {
return new $In(params, owneryQuery, options, name);
};

export const $lt = numericalOperation(params => b => b < params);
export const $lte = numericalOperation(params => b => b <= params);
Expand Down
9 changes: 9 additions & 0 deletions test/basic-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -584,5 +584,14 @@ describe(__filename + "#", function() {
}
})
);

assert.deepEqual(result, [
{
tags: ["animal", "dog"]
},
{
tags: ["animal", "cat"]
}
]);
});
});

0 comments on commit 3d1bf29

Please sign in to comment.