Skip to content

Commit

Permalink
feat(deep): implement or operator and tests
Browse files Browse the repository at this point in the history
- Add or operator implementation in Deep class
- Implement proper set merging for or operations
- Add comprehensive test for or operator
- Clean up error messages
- Fix AnyGet method to return undefined for non-matches
  • Loading branch information
ivansglazunov committed Nov 23, 2024
1 parent af2fd08 commit 4bfe2a8
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 20 deletions.
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ All methods work uniformly across different data types, treating single items as
- Logical operators for filtering:
- [x] `and` - Array of expressions that all must match
- [x] `not` - Expression that must not match
- [ ] `or` - Array of expressions where at least one must match
- [x] `or` - Array of expressions where at least one must match
- Condition types (comparison operators):
- [ ] `eq` - Equal to
- [ ] `neq` - Not equal to
Expand Down Expand Up @@ -249,14 +249,14 @@ const B = deep.new();
const C = deep.new();
// Create instances
const a1 = deep.new();
const b1 = deep.new();
const c1 = deep.new();
// Set types for instances
a1.type = A; // a1 is of type A
b1.type = B; // b1 is of type B
c1.type = C; // c1 is of type C
const a1 = A.new();
const b1 = B.new();
const c1 = C.new();
// (If we create a1,b1,c1 from deep.new(), not from A,B,C.new()), type can be setted manually:
// a1.type = A; // a1 is of type A
// b1.type = B; // b1 is of type B
// c1.type = C; // c1 is of type C
// Create relationships
a1.from = b1; // a1 points from b1
Expand Down
28 changes: 17 additions & 11 deletions src/deep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ export class Deep {
deep.contains.AnyHas = deep.contains.MethodHas.new((current, it) => current.call === it);
_insert(deep.contains.Compatable, deep.contains.AnyHas, deep.contains.Any);

deep.contains.AnyGet = deep.contains.MethodGet.new((current, it) => current.call === it ? it : it);
deep.contains.AnyGet = deep.contains.MethodGet.new((current, it) => current.call === it ? it : undefined);
_insert(deep.contains.Compatable, deep.contains.AnyGet, deep.contains.Any);

deep.contains.AnySize = deep.contains.MethodSize.new((current) => 1);
Expand Down Expand Up @@ -485,7 +485,7 @@ export class Deep {
_insert(deep.contains.Compatable, deep.contains.SetAdd, deep.contains.Set);

deep.contains.SetSet = deep.contains.MethodSet.new((current, key, value) => {
if (key !== value) throw new Error(`💁 Can't set into Set when key != value`);
if (key !== value) throw new Error(` Can't set into Set when key != value`);
current.call.add(value);
return current;
});
Expand Down Expand Up @@ -924,7 +924,7 @@ export class Deep {
return current;
} else {
for (let id of ids) return id.call;
throw new Error(`🤔 Unexpected, ids can't be empty here.`);
throw new Error(` Unexpected, ids can't be empty here.`);
}
}

Expand All @@ -943,7 +943,7 @@ export class Deep {
set value(value) {
const previous = this.call;
if (isUndefined(value)) {
if (isValue(this.value)) throw new Error(`🤦 If .value is Value, it's can't be ereised!`);
if (isValue(this.value)) throw new Error(` If .value is Value, it's can't be ereised!`);
this.deep.memory.values.unset(this);
} else if (isValue(value) && this.type == this.deep.Id) {
this.deep.memory.values.unset(this);
Expand All @@ -954,7 +954,7 @@ export class Deep {
} else if (isDeep(value) && isValue(value.value)) {
this.deep.memory.values.unset(this);
this.deep.memory.values.set(this, value);
} else throw new Error('🙅 Value must be isValue(value) or isValue(value.value) or isUndefined(value)');
} else throw new Error(' Value must be isValue(value) or isValue(value.value) or isUndefined(value)');
const current = this.value;
if (previous !== current) {
const event = this._createChangeEvent('change', 'value', previous, current);
Expand Down Expand Up @@ -1195,8 +1195,8 @@ export class Deep {
else {
const valued = this.deep.memory.values.many(value);
if (valued.size) {
if (!valued.size) throw new Error(`🤔 Unexpected, value can't be in all, but not values.`);
if (valued.size != 1) throw new Error(`🤔 Unexpected, value can only one Deep in .memory.values.many.`);
if (!valued.size) throw new Error(` Unexpected, value can't be in all, but not values.`);
if (valued.size != 1) throw new Error(` Unexpected, value can only one Deep in .memory.values.many.`);
for (let v of valued) {
return v;
}
Expand Down Expand Up @@ -1451,7 +1451,7 @@ export class Deep {
* @returns Expanded deep.Exp
*/
exp(input: any, selection: Deep) {
if (isDeep(input) || (!isObject(input))) throw new Error(`🙅 Exp must be plain object or array for and operator`);
if (isDeep(input) || (!isObject(input))) throw new Error(` Exp must be plain object or array for and operator`);
const exp: any = this.deep.Exp.new({});

if (isArray(input)) {
Expand All @@ -1476,7 +1476,7 @@ export class Deep {
this.exp(input[key], nestedSelection);
exp.call[key] = nestedSelection;
nestedSelection.on((e) => relation.emit(e));
} else throw new Error(`🙅 Only Deep or plain objects Exp can be value in exp (${key})!`);
} else throw new Error(` Only Deep or plain objects Exp can be value in exp (${key})!`);
relation.from = selection;
relation.to = exp.call[key];
relation.on((e) => selection.emit(e));
Expand Down Expand Up @@ -1530,6 +1530,12 @@ export class Deep {
set = arrayOfSets.reduce((result, set) => {
return result.intersection(set.call);
}, currentSet);
} else if (relation.typeof(this.deep.contains.or)) {
const arrayOfSets = relation.to.call();
set = arrayOfSets.reduce((result, item) => {
const itemSet = item.call;
return result ? new Set([...result, ...itemSet]) : itemSet;
}, set);
}
} else if (relation.typeof(this.deep.Order)) {
const nextSet = relation.to.call();
Expand Down Expand Up @@ -1764,8 +1770,8 @@ export class Contains {
return founded;
},
set(target, key, value, receiver) {
if (key === 'deep') throw new Error('🙅 Key "deep" is reserved in contains!');
if (!isDeep(value)) throw new Error('🙅 Value must be Deep!');
if (key === 'deep') throw new Error(' Key "deep" is reserved in contains!');
if (!isDeep(value)) throw new Error(' Value must be Deep!');
let founded: Deep | void = undefined;
const Contain = target.deep.deep.Contain;
for (let contain of target.deep.out.call) {
Expand Down
33 changes: 33 additions & 0 deletions src/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ test(`Symbol methods`, () => {
assert.equal(d.has(Symbol()), false);

assert.equal(d.get(value), value);
assert.equal(d.get(Symbol()), undefined);

assert.equal(d.size, 1);
assert.deepEqual(d.map(v => v), [value]);
assert.equal(d.add(value), value);
Expand All @@ -302,6 +304,8 @@ test(`String methods`, () => {
assert.equal(d.has('def'), false);

assert.equal(d.get(value), value);
assert.equal(d.get('def'), undefined);

assert.equal(d.size, 3);
assert.deepEqual(d.map(v => v), [value]);
assert.equal(d.add(value), value);
Expand All @@ -324,6 +328,8 @@ test(`Number methods`, () => {
assert.equal(d.has(234), false);

assert.equal(d.get(value), value);
assert.equal(d.get(234), undefined);

assert.equal(d.size, 3);
assert.deepEqual(d.map(v => v), [value]);
assert.equal(d.add(value), value);
Expand All @@ -346,6 +352,8 @@ test(`BigInt methods`, () => {
assert.equal(d.has(BigInt(234)), false);

assert.equal(d.get(value), value);
assert.equal(d.get(BigInt(234)), undefined);

assert.equal(d.size, 3);
assert.deepEqual(d.map(v => v), [value]);
assert.equal(d.add(value), value);
Expand Down Expand Up @@ -677,6 +685,31 @@ test('and operator', () => {
});
});

test('or operator', () => {
const deep = new Deep();

// Create test instances
const Type1 = deep.new();
const Type2 = deep.new();
const instance1 = Type1.new();
const instance2 = Type1.new();
const instance3 = Type1.new();

// Test or operator
const orQuery = deep.select({
or: [
{ type: Type1 },
{ type: Type2 }
]
});

const result = orQuery.call();
assert(result.has(instance1));
assert(result.has(instance2));
assert(result.has(instance3));
assert.equal(result.size, 3);
});

test('association events order', () => {
const deep = new Deep();
const events: DeepEvent[] = [];
Expand Down

0 comments on commit 4bfe2a8

Please sign in to comment.