Having the following record:
data Sleep = Sleep
{ _duration :: Maybe Int
, _drunk :: Bool
}
Is there a way to do the following:
deriveSomething ''Sleep
fieldName duration :: String -- "duration"
I need this for typesafe DB specific field updates, i.e:
setField connection key duration (Just 50)
It needs to be DB-agnostic though (thus opaleye etc. is out).
(If this can be achieved with a standard package like lens even better, but I wasn't able to find anything.)
You can do this using Data.Data:
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Data
data Sleep = Sleep
{ _duration :: Maybe Int
, _drunk :: Bool
} deriving (Typeable, Data)
fieldNames :: Data a => a -> [String]
fieldNames = constrFields . toConstr
Example:
> fieldNames (Sleep undefined undefined)
["_duration", "_drunk"]
You'll have to decide how you want to transform the names to database columns after that, but that should be fairly easy.
This requires a value created using a particular constructor, remember that data types can have many constructors. There isn't really a way around this, but you could have something like
sleepFieldNames :: [String]
sleepFieldNames = fieldNames (Sleep undefined undefined)
So that you don't have to keep recalculating it.
Related
I am currently in a bit of a bind.
struct sectionWithDatesAsName {
var sectionName : String
var sectionObjects : [SoloTransactionModel]!
init(uniqueSectionName: String?, sectionObject: [SoloTransactionModel]?) {
sectionName = uniqueSectionName ?? "nil"
if let section = sectionObject {
sectionObjects = section.reversed()
}
}
}
I currently have an array of sectionWithDatesAsName. And I can work with it, display in the tableView among other things.
The bind comes up when I want to check some information in the sectionObject before displaying it on the tableView.
I want to check the type of the sectionObject which is saved in the object itself.
How do I check the information in the sectionObject without slowing down the app? Or have a horrible time complexity calculated?
(Note: I can't change the format of the struct has this has already been used by a whole lot of other processes)
Write a function in your sectionWithDatesAsName with the signature filteredSections(type: sectionType) -> sectionWithDatesAsName
(If you don't have the ability to edit the definition of sectionWithDatesAsName you can create an extension that adds the above function)
If the sectionWithDatesAsName is defined elsewhere, define this function in an extension.
When you call it, build a new sectionWithDatesAsName object by filtering the arrays to match the specified type.
Use the resulting filtered sectionWithDatesAsName object as the data model for your table view. It will be built once and used for the lifetime of the tableView, so you will pay an O(n) time cost to filter it once when you create it.
I'm creating a button that when clicked adds the current date and time to an array but when I try to append to the array it only appends once and not repeating the process
the Entries struct:
struct Enteries {
var dates:[String] = []
}
convert date to String:
func DateConverter(){
format.timeZone = .current
format.dateFormat = "yyyy-MM-dd HH:mm"
dateString = format.string(from: currentDate)
}
The function that appends: also its called later whenever an IBAction is triggered
func AddToDatabase () {
var entery = Enteries()
entery.dates.append(dateString)
print(entery.dates)
}
`
Yikes, there's a lot going on here.
First of all, Swift's convention is to use lowerCamelCase for functions. Only type names should be UpperCamelCase.
Secondly, function names should be verbs or verb phrases, type names should be nouns. If I saw DateConverter in some code, I would expect it to be a type. It's an UpperCamelCase noun, that's how types should be named. But yours is a function (which would be a total surprise to every other Swift developer, because it violates the expectations they've built up from Swift's naming conventions), that function should probably be called parseDate.
Which way does DateConverter convert? From String to Date, Date to String, or both? What's its input? What's it's output? These things should be obvious from a good function name, but are totally unknown here without looking at the implementation.
Critically, the DateConverter function doesn't take input from parameters, and doesn't return a result, instead it takes input from a side effect (accessing the variable currentDate) and returns a result via side effect (writing to an a variable dateString). This is really bad, for several reasons:
It's not reusable. You have no way to use this date parsing code somewhere else without copy/pasting it, which is how code duplication and complexity arise. If you ever decide to change the date format in your app, you won't have a central source-of-truth that you can change, instead you'll have to manually hunt down every copy of this function, and change it, hoping you don't miss any. Not good.
It's not thread safe
It's more complex than a simple function that has type (Date) -> String. It obfuscates what's going on.
It defies peoples' expectations, without justification.
Enteries.dates has a default value of [], which doesn't seem to be a good idea if you're going to be appending to it as soon as you create it. Instead, take the array via an initializer parameter.
Enteries.dates has type [String]. Why?! You already have Date objects, store those!
They're smaller (in memory)
They're presentation-agnostic, meaning you can properly format them for different interfaces and different locales at a later time, as necessary
They support date math. I often see people storing dates as strings, and ask questions like "How do I sort my array of dates?" (which are actually stored as strings), "How do I add 1 day to "2019-12-24", and they start doing funky parsing, splitting, joining, and it's all just an absolute mess
Here's how I would improve this code:
struct Entries {
var entries: [Entry]
}
struct Entry {
let date: Date
}
// Call this from your view layer, only when you're about to present a `Date` to a user.
func parse(date: Date) -> String {
let df = DateFormatter()
df.timeZone = .current
df.dateFormat = "yyyy-MM-dd HH:mm"
return format.string(from: currentDate)
}
var entries = Entries(entries: [])
func addToDatabase(entry: Entry) {
entries.append(entry)
print(enteries.entries)
}
you are creating a new entery object eveytime the function is called. SO its creating a new object everytime. Declare your entery object outside the function.
var entery = Enteries()
func AddToDatabase () {
entery.dates.append(dateString)
print(entery.dates)
}
Core data is still a bit new for me, so I don't quite understand the ins and outs. I understand how to save the basics like Strings, Ints, etc in core data, but I don't quite understand how to save an array of custom objects into core data, or if that is even possible. From my research, my current understanding is I need to set the attribute to Binary Data, and set its identifier to [exercise] (making a fitness application). Unfortunately when I try to pass my array into the managed context, I get an error in my code that reads "Cannot assign value of type '[Exercise]' to type 'Data?'"
func save (completion: (_ finished: Bool) -> ()){
guard let managedContext = appDelegate?.persistentContainer.viewContext else { return }
let workout = Workout(context: managedContext)
workout.nameOfWorkout = workoutNameField.text
workout.exercises = exercises // error appears on this line, both "exercises" are arrays
}
I guess my question is, is what I am attempting to do even possible? If so, what steps am I missing? I read somewhere to convert the array into NSData, and change it back when it needs to be accessed, but my concern is that when I try to change it back, it won't work as planned. Sorry for the long winded question, just want to make sure I'm including all details I can think of.
For storing custom types in CoreData, the fastest way is:
making your custom types (Exercise) subclass of NSObject
setting the attribute's type in the core data model to Transformable
setting the CustomClass to [Exercise]
So you have to define your Exercise class similar to:
public class Exercise: NSObject {
let name: String
let duration: TimeInterval
init(name: String, duration: TimeInterval) {
self.name = name
self.duration = duration
}
}
Then you go to the model definition and set the attribute type and CustomClass field:
CoreData Model Example
You can now use your save function as:
func save (completion: (_ finished: Bool) -> ()){
guard let managedContext = appDelegate?.persistentContainer.viewContext else { return }
let workout = Workout(context: managedContext)
workout.nameOfWorkout = workoutNameField.text
workout.exercises = exercises
}
I am new in CoreData and I am trying to fetch only one column Data. I am trying using below code:
//MARK :- Fetch All Calculation
func fetchUniqueParentAxis(testID : String) -> [String] {
var arrAxis : [String] = []
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "TesCalculation")
fetchRequest.predicate = NSPredicate(format: "testID == %# ",testID)
fetchRequest.includesPropertyValues = true
fetchRequest.returnsObjectsAsFaults = false
fetchRequest.propertiesToFetch = ["parentAxis"]
do {
calculation = try AppDelegate.getContext().fetch(fetchRequest) as! [TesCalculation]//try AppDelegate.getContext().fetch(fetchRequest) as! [String : AnyObject]
}
catch let error {
//Handle Error
Helper.sharedInstance.Print(error as AnyObject)
}
}.
"parentAxis" is my a column and I want to fetch data of that column only .
You can absolutely fetch a subset of columns in CoreData. Yes, I agree Core Data IS an Object Graph solution that can use SQLite as a storage engine. However, fetching a subset of data instead of an entire NSManagedObject has been possible to do for a very long time in CoreData but recent changes have made it slightly different than before.
let fetchRequest = NSFetchRequest<NSDictionary>(entityName: TesCalculation.entity().name!)
fetchRequest.resultType = .dictionaryResultType
fetchRequest.predicate = NSPredicate(format: "testID == %# ",testID)
fetchRequest.propertiesToFetch = ["parentAxis"]
do {
let results = try AppDelegate.getContext().fetch(fetchRequest)
} catch let error as NSError {
print(error)
}
What this will return you is something that looks like this:
[
{
"parentAxis": "abc"
},
{
"parentAxis": "xyz"
}
]
The question was not about performance gain (even though there might be; I truly have no idea!) but rather if/how this can be done and this is how it can be done. Plus, I disagree with other statements made that it "doesn't make sense to have a property without an object." There are plenty of cases where you are allocating objects where all you need is a property or two for the need. This also comes in handy if you are loosely coupling Entities between multiple stores. Of course there are other methods for this as well (your xcdatamodel's Fetched Properties) so it just really depends on the use case.
Just to show that it has been around for some time this is in the header of the NSFetchRequest under NSFetchRequestResultType:
#available(iOS 3.0, *)
public static var dictionaryResultType: NSFetchRequestResultType { get }
Core data is an object model. It translates rows of the sql database into objects with properties. You are not running queries directly on the SQL, so you cannot do everything in core-data that you could do with SQL. You interact with object which interact with the database. In core-data you can have an object that is not faulted. It means that none of its properties are loaded into memory, but when you need them (when you access a property) it will fetch it from the database. You cannot have a object that has only some of its properties set. They are either all set (ie faulted) or none are set (it is not faulted).
There really isn't much to be gained in most cased by only fetch one or two columns. The extra data transfer is often minimal. The only exception is when you have a large blob of data as as property on the object. In that case you should store the blob on a separate entity and give it a one-to-one relationship. That way the expensive block of data isn't loaded into memory until it is requested.
I'm sorry for my bad english if somethig is not clear please ask me and I will explain.
My goal is make back end in OCaml for start to "play seriusly" with this language, I chose to do beck end project because I wanna make front end too in React for improve my skill with React too (I use OCaml for passion, and Ract for job I'm web developer)
I chose sqlite (with this lib: http://mmottl.github.io/sqlite3-ocaml/api/Sqlite3.html) as db for avoid db configuration
I have idea to make little wrapper for db calls(so if I chose to change db type I just need to change it), and make a function like this:
val exec_query : query -> 'a List Deferred.t = <fun>
but in lib I see this signature for exec function:
val exec : db -> ?cb:(row -> headers -> unit) -> string -> Rc.t = <fun>
The result is passed row by row to callback, but for my purpose I think I need to have some kind of object (list, array, etc.), but I have no idea how to make it from this function.
Can someone suggest how to proceed?
I guess you want val exec_query : query -> row List Deferred.t. Since Sqlite3 does not know about Async, you want to execute the call returning the list of rows in a separate system thread. The function In_thread.run : (unit -> 'a) -> 'a Deferred.t (optional args removed from signature) is the function to use for that. Thus you want to write (untested):
let exec_query db query =
let rows_of_query () =
let rows = ref [] in
let rc = Sqlite3.exec_no_headers db query
~cb:(fun r -> rows := r :: !rows) in
(* Note: you want to use result to handle errors *)
!rows in
In_thread.run rows_of_query