Skip to content

Commit 4bfe2a8

Browse files
committed
feat(deep): implement or operator and tests
- 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
1 parent af2fd08 commit 4bfe2a8

File tree

3 files changed

+59
-20
lines changed

3 files changed

+59
-20
lines changed

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ All methods work uniformly across different data types, treating single items as
196196
- Logical operators for filtering:
197197
- [x] `and` - Array of expressions that all must match
198198
- [x] `not` - Expression that must not match
199-
- [ ] `or` - Array of expressions where at least one must match
199+
- [x] `or` - Array of expressions where at least one must match
200200
- Condition types (comparison operators):
201201
- [ ] `eq` - Equal to
202202
- [ ] `neq` - Not equal to
@@ -249,14 +249,14 @@ const B = deep.new();
249249
const C = deep.new();
250250
251251
// Create instances
252-
const a1 = deep.new();
253-
const b1 = deep.new();
254-
const c1 = deep.new();
255-
256-
// Set types for instances
257-
a1.type = A; // a1 is of type A
258-
b1.type = B; // b1 is of type B
259-
c1.type = C; // c1 is of type C
252+
const a1 = A.new();
253+
const b1 = B.new();
254+
const c1 = C.new();
255+
256+
// (If we create a1,b1,c1 from deep.new(), not from A,B,C.new()), type can be setted manually:
257+
// a1.type = A; // a1 is of type A
258+
// b1.type = B; // b1 is of type B
259+
// c1.type = C; // c1 is of type C
260260
261261
// Create relationships
262262
a1.from = b1; // a1 points from b1

src/deep.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ export class Deep {
383383
deep.contains.AnyHas = deep.contains.MethodHas.new((current, it) => current.call === it);
384384
_insert(deep.contains.Compatable, deep.contains.AnyHas, deep.contains.Any);
385385

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

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

487487
deep.contains.SetSet = deep.contains.MethodSet.new((current, key, value) => {
488-
if (key !== value) throw new Error(`💁 Can't set into Set when key != value`);
488+
if (key !== value) throw new Error(` Can't set into Set when key != value`);
489489
current.call.add(value);
490490
return current;
491491
});
@@ -924,7 +924,7 @@ export class Deep {
924924
return current;
925925
} else {
926926
for (let id of ids) return id.call;
927-
throw new Error(`🤔 Unexpected, ids can't be empty here.`);
927+
throw new Error(` Unexpected, ids can't be empty here.`);
928928
}
929929
}
930930

@@ -943,7 +943,7 @@ export class Deep {
943943
set value(value) {
944944
const previous = this.call;
945945
if (isUndefined(value)) {
946-
if (isValue(this.value)) throw new Error(`🤦 If .value is Value, it's can't be ereised!`);
946+
if (isValue(this.value)) throw new Error(` If .value is Value, it's can't be ereised!`);
947947
this.deep.memory.values.unset(this);
948948
} else if (isValue(value) && this.type == this.deep.Id) {
949949
this.deep.memory.values.unset(this);
@@ -954,7 +954,7 @@ export class Deep {
954954
} else if (isDeep(value) && isValue(value.value)) {
955955
this.deep.memory.values.unset(this);
956956
this.deep.memory.values.set(this, value);
957-
} else throw new Error('🙅 Value must be isValue(value) or isValue(value.value) or isUndefined(value)');
957+
} else throw new Error(' Value must be isValue(value) or isValue(value.value) or isUndefined(value)');
958958
const current = this.value;
959959
if (previous !== current) {
960960
const event = this._createChangeEvent('change', 'value', previous, current);
@@ -1195,8 +1195,8 @@ export class Deep {
11951195
else {
11961196
const valued = this.deep.memory.values.many(value);
11971197
if (valued.size) {
1198-
if (!valued.size) throw new Error(`🤔 Unexpected, value can't be in all, but not values.`);
1199-
if (valued.size != 1) throw new Error(`🤔 Unexpected, value can only one Deep in .memory.values.many.`);
1198+
if (!valued.size) throw new Error(` Unexpected, value can't be in all, but not values.`);
1199+
if (valued.size != 1) throw new Error(` Unexpected, value can only one Deep in .memory.values.many.`);
12001200
for (let v of valued) {
12011201
return v;
12021202
}
@@ -1451,7 +1451,7 @@ export class Deep {
14511451
* @returns Expanded deep.Exp
14521452
*/
14531453
exp(input: any, selection: Deep) {
1454-
if (isDeep(input) || (!isObject(input))) throw new Error(`🙅 Exp must be plain object or array for and operator`);
1454+
if (isDeep(input) || (!isObject(input))) throw new Error(` Exp must be plain object or array for and operator`);
14551455
const exp: any = this.deep.Exp.new({});
14561456

14571457
if (isArray(input)) {
@@ -1476,7 +1476,7 @@ export class Deep {
14761476
this.exp(input[key], nestedSelection);
14771477
exp.call[key] = nestedSelection;
14781478
nestedSelection.on((e) => relation.emit(e));
1479-
} else throw new Error(`🙅 Only Deep or plain objects Exp can be value in exp (${key})!`);
1479+
} else throw new Error(` Only Deep or plain objects Exp can be value in exp (${key})!`);
14801480
relation.from = selection;
14811481
relation.to = exp.call[key];
14821482
relation.on((e) => selection.emit(e));
@@ -1530,6 +1530,12 @@ export class Deep {
15301530
set = arrayOfSets.reduce((result, set) => {
15311531
return result.intersection(set.call);
15321532
}, currentSet);
1533+
} else if (relation.typeof(this.deep.contains.or)) {
1534+
const arrayOfSets = relation.to.call();
1535+
set = arrayOfSets.reduce((result, item) => {
1536+
const itemSet = item.call;
1537+
return result ? new Set([...result, ...itemSet]) : itemSet;
1538+
}, set);
15331539
}
15341540
} else if (relation.typeof(this.deep.Order)) {
15351541
const nextSet = relation.to.call();
@@ -1764,8 +1770,8 @@ export class Contains {
17641770
return founded;
17651771
},
17661772
set(target, key, value, receiver) {
1767-
if (key === 'deep') throw new Error('🙅 Key "deep" is reserved in contains!');
1768-
if (!isDeep(value)) throw new Error('🙅 Value must be Deep!');
1773+
if (key === 'deep') throw new Error(' Key "deep" is reserved in contains!');
1774+
if (!isDeep(value)) throw new Error(' Value must be Deep!');
17691775
let founded: Deep | void = undefined;
17701776
const Contain = target.deep.deep.Contain;
17711777
for (let contain of target.deep.out.call) {

src/test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,8 @@ test(`Symbol methods`, () => {
280280
assert.equal(d.has(Symbol()), false);
281281

282282
assert.equal(d.get(value), value);
283+
assert.equal(d.get(Symbol()), undefined);
284+
283285
assert.equal(d.size, 1);
284286
assert.deepEqual(d.map(v => v), [value]);
285287
assert.equal(d.add(value), value);
@@ -302,6 +304,8 @@ test(`String methods`, () => {
302304
assert.equal(d.has('def'), false);
303305

304306
assert.equal(d.get(value), value);
307+
assert.equal(d.get('def'), undefined);
308+
305309
assert.equal(d.size, 3);
306310
assert.deepEqual(d.map(v => v), [value]);
307311
assert.equal(d.add(value), value);
@@ -324,6 +328,8 @@ test(`Number methods`, () => {
324328
assert.equal(d.has(234), false);
325329

326330
assert.equal(d.get(value), value);
331+
assert.equal(d.get(234), undefined);
332+
327333
assert.equal(d.size, 3);
328334
assert.deepEqual(d.map(v => v), [value]);
329335
assert.equal(d.add(value), value);
@@ -346,6 +352,8 @@ test(`BigInt methods`, () => {
346352
assert.equal(d.has(BigInt(234)), false);
347353

348354
assert.equal(d.get(value), value);
355+
assert.equal(d.get(BigInt(234)), undefined);
356+
349357
assert.equal(d.size, 3);
350358
assert.deepEqual(d.map(v => v), [value]);
351359
assert.equal(d.add(value), value);
@@ -677,6 +685,31 @@ test('and operator', () => {
677685
});
678686
});
679687

688+
test('or operator', () => {
689+
const deep = new Deep();
690+
691+
// Create test instances
692+
const Type1 = deep.new();
693+
const Type2 = deep.new();
694+
const instance1 = Type1.new();
695+
const instance2 = Type1.new();
696+
const instance3 = Type1.new();
697+
698+
// Test or operator
699+
const orQuery = deep.select({
700+
or: [
701+
{ type: Type1 },
702+
{ type: Type2 }
703+
]
704+
});
705+
706+
const result = orQuery.call();
707+
assert(result.has(instance1));
708+
assert(result.has(instance2));
709+
assert(result.has(instance3));
710+
assert.equal(result.size, 3);
711+
});
712+
680713
test('association events order', () => {
681714
const deep = new Deep();
682715
const events: DeepEvent[] = [];

0 commit comments

Comments
 (0)