1

Hi all,

looking for support for a CoreData wrapper framework called Graph from CosmicMind (https://github.com/CosmicMind/Graph).

There's unfortunately rather little documentation beyond the absolute basics (though there seem to be a lot of quite powerful concepts introduced b.t.w.).

I wonder if somebody could - please - help me out with how to select/filter Entities in a 1:N relationship.

Given the following structure...

import Graph

let graph = Graph()
graph.clear()

let sectionA = Entity(type: "Section")
sectionA["id"] = 12
sectionA["name"] = "SectionA"

let sectionB = Entity(type: "Section")
sectionB["id"] = 2
sectionB["name"] = "SectionB"

let unitA = Entity(type: "Unit")
unitA["id"] = 122
unitA["name"] = "UnitA"
unitA["isExpensive"] = false
unitA.is(relationship: "UnitOfSection").of(sectionA)

let unitB = Entity(type: "Unit")
unitB["id"] = 19
unitB["name"] = "UnitB"
unitB["isExpensive"] = false
unitB.is(relationship: "UnitOfSection").of(sectionB)

let unitC = Entity(type: "Unit")
unitC["id"] = 7
unitC["name"] = "UnitC"
unitC["isExpensive"] = true
unitC.is(relationship: "UnitOfSection").of(sectionA)

let unitD = Entity(type: "Unit")
unitD["name"] = "UnitD"
unitD["isExpensive"] = true
unitD["id"] = 4
unitD.is(relationship: "UnitOfSection").of(sectionA)

graph.sync()

let unitsSearch = Search<Entity>(graph: graph).for(types: "Unit")
let units = unitsSearch.sync()

... I'd like to get only those Entities which have a "UnitOfSection" relationship to sectionA AND which have a property "isExpensive" with value false.

Any idea how to achieve this?

Thanks + best whishes

gresch
  • 440
  • 5
  • 11
  • Try: `let units = unitsSearch.sync().filter { ($0["isExpensive"] as? Bool) == false && !$0.relationship(types: "UnitOfSection").isEmpty } ` – Orkhan Alikhanov Aug 29 '18 at 07:41
  • Hi @OrkhanAlikhanov, thanks very much for your comment. I updated the example to make it more precise and added a 4th Entity. The expected result should be only one Entity (i.e. unitA as this has a "UnitOfSection" relationship to sectionA AND has an attribute of "isExpensive" == false). Your approach seems to only filter the isExpensive == false items and results in a count of 2. See a playground here: https://github.com/karstengresch/graphplaygrounds (Sub-Page: "Graph Relationship I", I actually didn't want to publish it yet as not ready.) – gresch Aug 29 '18 at 20:30
  • Ah that's really great! FYI, there is a new API that has been merged. See [CosmicMind/Graph#/154](https://github.com/CosmicMind/Graph/pull/154) – Orkhan Alikhanov Aug 29 '18 at 21:39
  • Can you check with the following filter closure? `($0["isExpensive"] as? Bool) == false && $0.relationship(types: "UnitOfSection").contains(sectionA)` – Orkhan Alikhanov Aug 29 '18 at 21:41
  • Thanks @OrkhanAlikhanov! Unfortunately Graph dev branch doesn't compile here (getting Search.swift:72:27: error: value of type 'Predicate' has no member 'map' self.predicate = self.predicate.map { ~~~~~^~~~~~~~~ ~~~ for most of the Graph API classes). Using 2.2.2, I get: "error: cannot convert value of type 'Entity' to expected argument type 'Relationship' ($0["isExpensive"] as? Bool) == false && $0.relationship(types: "UnitOfSection").contains(sectionA) ^~~~~~~~" – gresch Aug 30 '18 at 10:42
  • For latest code you have to use xcode10, don't forget to clear the build before rebuilding. – Orkhan Alikhanov Aug 31 '18 at 00:48
  • Sorry for providing non-compiling code, I need to test it to make sure If I can make it work – Orkhan Alikhanov Aug 31 '18 at 00:49
  • You could clone the above mentioned playground, run carthage and you should be up and ready...? B.t.w. - I'd be very grateful if you could upvote the question as I want to achieve 50pts to be able submitting comments... – gresch Aug 31 '18 at 15:30

1 Answers1

1

This should work:

let units = Search<Entity>(graph: graph).for(types: "Unit").sync().filter { entity in
    (entity["isExpensive"] as? Bool) == false && 
    entity.relationship(types: "UnitOfSection").contains(where: { relationship in
        relationship.object == sectionA
    })
}

What we do is:

  1. Fetch all "Unit" Entities
  2. Filter entities that has isExpensive = false
  3. And fetch "UnitOfSection" relationships of each entity and test if that relationship's object is sectionA
Orkhan Alikhanov
  • 9,122
  • 3
  • 39
  • 60
  • Thank you so much, @Orkhan - this is the correct and accepted answer! I tried a lot but the real trick I couldn't find was 'relationship in relationship.object == sectionA'. This longer this day lasts, the getter it bets. Wonderful solution! – gresch Aug 31 '18 at 20:36