core data predicate and expression madness - core-data

This is one for core data experts, I guess. Maybe this is just beyond the bounds of what it's supposed to... anyway:
on iOS, using sqlite persistent store.
I have entities like so:
A<-->>B<<-->C
B has an attribute 'v' which is a float, and another attribute 'd' which is a date.
B has relationship 'a' which is single to A, and 'c' which is single to C.
I can calculate the average of all B.v where B.a == someA, code is below. But, what I really want to do is calculate the average of all B.v where B.a == someA and where B is the last B for a C, ordered by B.d. So the average function would 'pick up' only one B for each C (the highest-dated one). Any ideas?
// create the fetch request
NSFetchRequest * request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:#"B" inManagedObjectContext:managedObjectContext]];
// create the expression
NSExpression * keyPathExpression = [NSExpression expressionForKeyPath:#"v"];
NSString * aggregationFunction = #"average:";
NSExpression * aggregationExpression = [NSExpression expressionForFunction:aggregationFunction arguments:[NSArray arrayWithObject:keyPathExpression]];
NSExpressionDescription * expressionDescription = [[NSExpressionDescription alloc] init];
[expressionDescription setName:#"aggregateValue"];
[expressionDescription setExpression:aggregationExpression];
[expressionDescription setExpressionResultType:NSDecimalAttributeType];
[request setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"a == %#", someA];
[request setPredicate:predicate];
[request setResultType:NSDictionaryResultType];
// Execute the fetch.
NSError * error = nil;
NSArray * objects = [managedObjectContext executeFetchRequest:request error:&error];

When you use setPropertiesToFetch: you are telling the fetch to ignore all other properties. This means your predicate of #"a == %#" which is keyed on the a attribute, is going to be ignored.
What you probably want to do in this case is to convert the #"a == %#" predicate into an NSSubqueryExpressionType equality expression and then make that the first expression in the array passed to setPropertiesToFetch:.
That will direct the fetch to first find all B objects that match #"a == %#" and then to run the v expression against that set of objects.
However, when you find yourself having to create convoluted predicates, that is usually an indication that your data model is poorly designed. Quite often, you end up with complex predicates because you are trying to create logical relationships within a predicate instead of modeling them in the data model.
Further, as a rule, when you have a particular object in a hand e.g. someAand/or someC then you don't do a fetch at all but instead you walk the relationships. Why fetch all B objects related to the someA object when you can just use someA.bObjects?
I think your data model really looks like this:
A<-->>B<<-->C
… and your looking for an intersection of B objects between the sets of someA.bs and someC.bs. So, the first thing to do is to get the intersection of the sets:
NSMutableSet *secSet=[[NSMutableSet setWithSet:someA.bs] intersectSet:someC.bs];
… now all you have to do is find the B object with the most recent date:
BClass *someB=[secSet valueForKeyPath:#"#max.dateAttribute"];
… and you're done. Iterate the process to find the intersections between multiple A and C objects.

Related

NSPredicate to detect non-empty relationships within a subquery

Given a core data entity setup as follows
Entity A
Bs -> B (many to many)
Cs -> C (many to many)
children -> Child (many to many)
Entity B
children -> Child (many to many)
Entity C
children -> Child (many to many)
Child
date
I've wanted to query for Entity A's where any of the children (in Entity A, B, or C) have dates that pass some query like being greater than a specified date.
Given the nested relationships some nested subqueries were required, so for checking all the Bs children from A with something like this
predicateString += "(SUBQUERY(Bs, $b, SUBQUERY($b.children, $child, $child.date >= %#).#count > 0).#count > 0)"
predicateVars = [testDate! as NSDate]
let predicate = NSPredicate(format: predicateString, argumentArray: predicateVars)
Repeating the same form of query for Cs and then just doing a single SUBQUERY for A's direct children.
This all works fine after some fine tuning of the predicate form (ensuring all the required counts were added).
The small problem arose when I wanted to now perform a similar search but instead of requiring the children's date to be greater than a test date I wanted to just find all A's who had any children in either A.children, Bs.children, Cs.children.
The nested SUBQUERIES caused problems, at first I thought it'd be fine to do a single level SUBQUERY and then check the count of the children relationship within it, so something like this
predicateString += " SUBQUERY(Bs, $b, $b.children.#count > 0).#count > 0"
Which is accepted as a valid predicate but when its evaluated you hit an exception
[error] error: exception handling request: <NSSQLFetchRequestContext: 0x60000018ec70> , Keypath containing KVC aggregate where there shouldn't be one; failed to handle $b.children.#count with userInfo of (null)
A quick search of stack overflow came up with the same error in this question
Keypath error with Core Data SUBQUERY and NSFetchedResultsController
Which seemed to suggest that you cannot do the #count within a SUBQUERY and therefore have to do another SUBQUERY over the children to get at the same result. Which would be the same form as my first example above, albeit I need a condition in my SUBQUERY that is always true for each element of the children. My first thought was hopefully that I could just use TRUE like this
predicateString += "(SUBQUERY(Bs, $b, SUBQUERY($b.children, $child, TRUE).#count > 0).#count > 0)"
It feels quite wasteful, but would do what I wanted. Unfortunately it fails to parse as a valid predicate.
Beyond this I have managed to succeed by making queries that should always be true, so comparing the date against 1970 as follows
let date1970 = Date.init(timeIntervalSince1970: 0)
predicateString += "(SUBQUERY(Bs, $b, SUBQUERY($b.children, $child, $child.date >= %#).#count > 0).#count > 0)"
predicateVars = [date1970! as NSDate]
This works, but feels like doing a bit more work than I'd prefer to just get a count. A simpler example that works is also just testing each child against nil, so
predicateString += "(SUBQUERY(Bs, $b, SUBQUERY($b.children, $child, $child != nil).#count > 0).#count > 0)"
predicateVars = [testDate! as NSDate]
This seems much better but I just wondered if there was a better option. I honestly don't understand why the TRUE condition alone isn't a valid predicate.. yes its wasteful, but it seems in this case we must do an effectively wasteful subquery to get the count we want.
Anyone got any better ideas?

Does [NSStream scheduleInRunLoop: forMode:] retain the NSStream?

I want to send and receive some data using nsstreams. I don't want to clutter my code so much, so I was wondering:
Do I need to keep a strong reference to a NSStream or is [NSStream scheduleInRunLoop: forMode:] creating a strong reference to it?
I couldn't find any documentation on that. I have tried, and it works without having an own strong reference.
I was hoping someone can confirm or refute that finding.
Yes, after scheduling NSStream in RunLoop its reference count grows. I think that this code is enough to prove it:
NSInputStream* nStream = [[NSInputStream alloc] initWithFileAtPath:path];
NSLog(#"Stream retain count A is %ld", CFGetRetainCount((__bridge CFTypeRef)nStream));
NSValue* val = [NSNumber valueWithPointer:(__bridge const void * _Nullable)(nStream)];// not increment reference counter
NSLog(#"Stream retain count B is %ld", CFGetRetainCount(val.pointerValue));
[nStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
NSLog(#"Stream retain count C is %ld", CFGetRetainCount(val.pointerValue));
nStream = nil;
NSLog(#"Stream retain count D is %ld", CFGetRetainCount(val.pointerValue));
And console output:
Stream retain count A is 1
Stream retain count B is 1
Stream retain count C is 3
Stream retain count D is 2
So adding to NSRunLoop increases number references by 2. After nullification of original strong reference counter value remains positive, and this prevents deallocation of stream object.
Because object still exist, will respond to this code:
[(__bridge const NSInputStream*)val.pointerValue open];
[(__bridge const NSInputStream*)val.pointerValue close];
But next line will cause crash - now stream is removed from NSRunLoop. All references to it was removed - what remains is value of pointer to - now deallocated - object (behaves similarly to assigned pointer). Call to deallocated object always means EXC_BAD_ACCESS...
NSLog(#"Stream retain count E is %ld",
CFGetRetainCount(val.pointerValue));//crash here

JPQL Query with calculated value?

I want to use a calculated value in the WHERE clause and in an ORDER BY expression. In plain sql it would look like
SELECT some, colums, (some arbitrary math) AS calc_value FROM table WHERE calc_value <= ? ORDER BY calc_value
If I try in JPQL
entitymanager.createQuery("SELECT e, (some arbitrary math) AS calc_value FROM Entity e WHERE calc_value <= :param ORDER BY calc_value", Entity.class);
it fails. Obviously, because the return of the query is the tuple of Entity and calc_value (i.e. Double).
Is there a way of getting this into one query, using strong typed return values (i.e. Entity.class, as the calculated value doesn't matter).
I've had a similar problem and didn't resolve the problem to fetch it into the correct object:
Tried all constructor combinations for the object - no luck.
tried Tuple.class - no luck.
Finally I used this approach and then fetched oject[0] into my real Java-Object:
TypedQuery<Object[]> q = em.createQuery("select v, (2 * 4) as temp from MyObject v order by temp", Object[].class);
List<Object[]> results = q.getResultList();
for (Object[] o : results)
MyObject mo = (MyObject) o[0];

Order an NSMutable array in descending order

I've been reading a few posts about ordering an NSMutable array but have had trouble getting it working, essentially I have a number of entries in a tableview, an unlimited amount can be added but I need to order them by an NSMutable array that contains numerical values, that would go well above 10. I'd really appreciate any help anyone could give me, I've been using the compare parameter but I can't seem to get it to reverse the order, secondly I read that numbers above 10 would start ordering in a strange way. Ill post y code shortly but anything for me to mull over would be great.
Thanks
The answer depends a bit on whether the objects in your array are numbers or strings. There are also various methods to sort arrays (sortUsingDescriptors, sortUsingComparator, ...).
If you have an array of numbers, you can sort them in decreasing order for example like this:
NSMutableArray *a = [NSMutableArray arrayWithObjects:#1, #55, #9, #17, nil];
[a sortUsingComparator:^NSComparisonResult(NSNumber *obj1, NSNumber *obj2) {
return -[obj1 compare:obj2];
}];
// Result: 55, 17, 9, 1.
Note the minus-sign in the comparator block which has the effect of reversing the order from increasing to decreasing.
If you have an array of strings, and you proceed in the same way, then you will get what you have called "that numbers above 10 would start ordering in a strange way":
NSMutableArray *a = [NSMutableArray arrayWithObjects:#"1", #"55", #"9", #"17", nil];
[a sortUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
return -[obj1 compare:obj2];
}];
// Result: 9, 55, 17, 1.
The object are sorted as strings, not as numbers.
The solution is to use the NSNumericSearch option:
NSMutableArray *a = [NSMutableArray arrayWithObjects:#"1", #"55", #"9", #"17", nil];
[a sortUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
return -[obj1 compare:obj2 options:NSNumericSearch];
}];
// Result: 55, 17, 9, 1.

Haskell Parsec and Unordered Properties

I am trying to use Parsec to parse something like this:
property :: CharParser SomeObject
property = do
name
parameters
value
return SomeObjectInstance { fill in records here }
I am implementing the iCalendar spec and on every like there is a name:parameters:value triplet, very much like the way that XML has a name:attributes:content triplet. Infact you could very easily convert an iCalendar into XML format (thought I can't really see the advantages).
My point is that the parameters do not have to come in any order at all and each paramater may have a different type. One parameter may be a string while the other is the numeric id of another element. They may share no similarity yet, in the end, I want to place them correctly in the right record fields for whatever 'SomeObjectInstance' that I wanted the parser to return. How do I go about doing this sort of thing (or can you point me to an example of where somebody had to parse data like this)?
Thankyou, I know that my question is probably a little confused but that reflects my level of understanding of what I need to do.
Edit: I was trying to avoid giving the expected output (because it is large, not because it is hidden) but here is an example of an input file (from wikipedia):
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
UID:uid1#example.com
DTSTAMP:19970714T170000Z
ORGANIZER;CN=John Doe:MAILTO:john.doe#example.com
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
SUMMARY:Bastille Day Party
END:VEVENT
END:VCALENDAR
As you can see it contains one VEvent inside a VCalendar, I have made data structures that represent them here.
I am trying to write a parser that parses that type of file into my data structures and I am stuck on the bit where I need to handle properties coming in any order with any type; date, time, int, string, uid, ect. I hope that makes more sense without repeating the entire iCalendar spec.
Parsec has the Parsec.Perm module precisely to parse unordered but linear (i.e. at the same level in the syntax tree) elements such as attribute tags in XML files.
Unfortunately the Perm module is mostly undocumented. The best reference is the Parsing Permutation Phrases paper which the Haddock doc page refers to, but even that is largely a description of the technique rather than how to use it.
Ok, so between BEGIN:VEVENT and END:VEVENT, you have many key value pairs. So write a rule keyValuePair that returns (key, value). Now inside the rule for VEVENT you do many KeyValuePair to get a list of pairs. Once you've done that you use a fold to populate a VEVENT record with the given values. In the function you give to fold, you use pattern matching to find out in which field to store the value. As the starting value for the accumulator you use a VEvent record where the optional fields are set to Nothing. Example:
pairs <- many keyValuePairs
vevent = foldr f (VEvent {sequence = Nothing}) pairs
where f ("SUMMARY", v) ve = ve {summary = v}
f ("DSTART", v) ve = ve {dstart = read v}
...and so on. Do the same for the other components.
Edit: Here's some runnable example code for the fold:
data VEvent = VEvent {
summary :: String,
dstart :: String,
sequenceSt :: Maybe String
} deriving Show
vevent pairs = foldr f (VEvent {sequenceSt = Nothing}) pairs
where f ("SUMMARY", v) ve = ve {summary = v}
f ("DSTART", v) ve = ve {dstart = v}
f ("SEQUENCEST", v) ve = ve {sequenceSt = Just v}
main = do print $ vevent [("SUMMARY", "lala"), ("DSTART", "lulu")]
print $ vevent [("SUMMARY", "lala"), ("DSTART", "lulu"), ("SEQUENCEST", "lili")]
Output:
VEvent {summary = "lala", dstart = "lulu", sequenceSt = Nothing}
VEvent {summary = "lala", dstart = "lulu", sequenceSt = Just "lili"}
Note that this will produce a warning when compiled. To avoid the warning, initialize all non-optional fields to undefined explicitly.

Resources