F-Script, the Cocoa-based scripting environment, now provides some great tools for exploring Core Data databases.
I couldn’t figure out how to easily open up my databases, other than manually creating a managed object model, then a persistent store coordinator, then a managed object context on the console. I couldn’t find any existing tools, and I wanted a quick workflow for opening up my databases, so I put together a script that prompts for the application bundle or .xcdatamodel(d)
data model file, then prompts for the XML (.xml
), binary (.binary
) or SQLite (.sql
or anything else) database file, and opens up the inspector.
I wrote it as an Applescript that just calls upon F-Script to evaluate the script, and saved it in an application bundle so I can pull it up quickly.
Here it is:
It just needs the F-Script app to be available.
Upon opening, the managed object context is available on the console as “context
“. So, aside from using F-Script’s object browser, you can also do things like:
> request := (NSFetchRequest alloc) init > request setEntity:(NSEntityDescription entityForName:'MyEntity' inManagedObjectContext:context) > request setPredicate:(NSPredicate predicateWithFormat:'type = 3') > result := context executeFetchRequest:request error:nil > result _PFArray { (entity: MyEntity; id: 0x20064c9e0 ; data: ), (entity: MyEntity; id: 0x20064c9c0 ; data: ), (entity: MyEntity; id: 0x200651180 ; data: ) ... |
Update: Now has better error reporting, and the option to load classes from a bundle.
For those interested, here’s the original F-Script:
panel := NSOpenPanel openPanel. panel setAllowedFileTypes:{'xcdatamodel', 'app', 'framework'};setTitle:'Data model';setMessage:'Select a data model file or bundle containing a data model'. classesButton := (NSButton alloc) initWithFrame:(00 extent:20030). classesButton setTitle:'Load classes in bundle';setButtonType:NSSwitchButton. panel setAccessoryView:classesButton. model := nil. [model == nil] whileTrue:[ error := FSPointer objectPointer. (panel runModal = NSFileHandlingPanelCancelButton) ifTrue:[ (NSException exceptionWithName:'CancelException' reason:'Cancelled' userInfo:nil) raise ] . (((panel URL) absoluteString) hasSuffix:'xcdatamodel') ifTrue:[ model := ((NSManagedObjectModel alloc) initWithContentsOfURL:(panel URL)) ] ifFalse:[ bundle := (NSBundle bundleWithURL:(panel URL)). (bundle == nil) ifFalse:[ model := (NSManagedObjectModel mergedModelFromBundles:{bundle}). (model ~~ nil & (FSBoolean booleanWithBool:(classesButton state) = NSOnState)) ifTrue:[ (FSBoolean booleanWithBool:(bundle loadAndReturnError:error)) ifFalse:[ model := nil. (NSAlert alertWithMessageText:'Could not load bundle' defaultButton:'OK' alternateButton:nil otherButton:nil informativeTextWithFormat:((error at:0) localizedDescription)) runModal ] ] ] ]. (model == nil & ((error at:0) == nil)) ifTrue:[ (NSAlert alertWithMessageText:'Could not load model from file or bundle' defaultButton:'OK' alternateButton:nil otherButton:nil informativeTextWithFormat:'') runModal ] ]. panel setAccessoryView:nil. store := ((NSPersistentStoreCoordinator alloc) initWithManagedObjectModel:model). panel setAllowedFileTypes:nil; setTitle:'Database file';setMessage:'Select Core Data SQLite database'. opened := nil. [opened == nil] whileTrue:[ (panel runModal = NSFileHandlingPanelCancelButton) ifTrue:[ (NSException exceptionWithName:'CancelException' reason:'Cancelled' userInfo:nil) raise ] . type := NSSQLiteStoreType. ((((panel URL) absoluteString) lowercaseString) hasSuffix:'xml') ifTrue:[type := NSXMLStoreType]. ((((panel URL) absoluteString) lowercaseString) hasSuffix:'binary') ifTrue:[type := NSBinaryStoreType]. error := FSPointer objectPointer. opened := (store addPersistentStoreWithType:type configuration:nil URL:(panel URL) options:nil error:error). (opened == nil) ifTrue:[ (NSAlert alertWithMessageText:'Could not load database' defaultButton:'OK' alternateButton:nil otherButton:nil informativeTextWithFormat:((error at:0) localizedDescription)) runModal ] ]. context := ((NSManagedObjectContext alloc) init). context setPersistentStoreCoordinator:store. context inspectWithSystem:sys |
This is totally awesome. It will help my testing immensely. Thanks for your contribution!!
I tried running your app against several xcdatamodel and sqlite database files and it always says that the filename is invalid. Very frustrating. Lots of swearing. Not impressed.
Any ideas?
Thanks
None, I’m afraid! Have you tried doing it the old fashioned way, in F-Script? (you can use the code above as a guide)
Works great for me on multiple projects. Considering it is, you know, FREE I would stop hating on someone who helps out the dev community.
Sorry for the confusion, my comment was directed at Randy.
This is brilliant thanks!
how would you write a predicate to check dates?
Say for User.createdDate
how can I write the predicate to fetch:
createDate < [NSDate date]
Thanks
Cheers =)
Try something like:
Can I suggest that you also allow the latest file type of “xcdatamodeld” too, just as a very minor tweak! :)
Sure! That should do it.
I still get a message from FScript 2.x saying “Could not load model from file or bundle”. This is from a model created with Xcode 4.2.
I’m getting same message as Mark. Any ideas?
If you like this you may also like the GitHub project CoreDataPro. You can find it here:
https://github.com/yepher/CoreDataUtility
CoreDataPro lets you view explore your core data data model and view data that your application has stored.