CodableFirebase icon indicating copy to clipboard operation
CodableFirebase copied to clipboard

How to map to FIRTimestamp

Open cerupcat opened this issue 6 years ago • 30 comments

I'm trying to figure out how map to FIRTimestamp since it's not codable currently. Is there a way to transform the data returned from FIRTimestamp to Date instead or make FIRTimestamp codable so that it maps correctly?

cerupcat avatar Apr 21 '18 19:04 cerupcat

Struggling with this as well as Firestore has now made the push to FIRTimestamp and .dateValue. Would be happy to do a PR for the feature if I could get a little guidance.

dannypier avatar May 08 '18 19:05 dannypier

@cerupcat I would not use this in production, but here's a hack I was able to get FIRTimestamps working with. Again... it's a HACK, be forewarned.

https://github.com/alickbass/CodableFirebase/pull/42

dannypier avatar May 09 '18 19:05 dannypier

Thanks, i'll take a look.

cerupcat avatar May 09 '18 19:05 cerupcat

Hey guys! First of all, sorry for being unresponsive lately... I am really glad that there is support from community!

About the issue. I think that the proper way to do it, would be to do something similar to here. So we can make FirTimestamp Encodable and it will be skipped and left untouched when encoding and thus will let the Firestore handle it. I will open a PR with an example of how to use it! What do you think about it?

alickbass avatar May 13 '18 12:05 alickbass

@alickbass would be great if we get some best practice guidance on that!

jonandersen avatar May 13 '18 17:05 jonandersen

Hey guys! The PR makes Timestamp conform to Codable and you can use it directly in your code just like normal Date. Something like below:

import CodableFirebase

extension Timestamp: TimestampType {}

struct FirTimestampModel: Codable {
  let timestamp: Timestamp
}

let timestamp = FirTimestampModel(timestamp: Timestamp(date: Date()))
let data = try! FirestoreEncoder().encode(timestamp)

If you want to use Date in your models and convert to Timestamp on server, I would really discourage that, as then you will lose all the precision.

alickbass avatar May 19 '18 17:05 alickbass

Thank you for your effort 👍

luca251117 avatar May 19 '18 18:05 luca251117

Thanks @alickbass! Agree to disagree about having Timestamp in your models though. Creating a dependency on Firestore for the Timestamp type at the model layer doesn't feel good to me.

dannypier avatar May 19 '18 18:05 dannypier

Well, I think that the reason to use FirTimestamp in the first place is that you are not satisfied with the precision of the Date. Why not use Date directly then?

alickbass avatar May 19 '18 18:05 alickbass

Yeah, I would prefer to use Date directly but a recent version of Firestore told (via a console message) that the using of Date was going to be deprecated and the correct thing to do was get dateValue of FIRTimestamp. That's actually the thing that got me involved in this issue, precision wasn't so much of a concern.

The behavior for system Date objects stored in Firestore is going to change AND YOUR APP MAY BREAK.
To hide this warning and ensure your app does not break, you need to add the following code to your app before calling any other Cloud Firestore methods:

let db = Firestore.firestore()
let settings = db.settings
settings.areTimestampsInSnapshotsEnabled = true
db.settings = settings

With this change, timestamps stored in Cloud Firestore will be read back as Firebase Timestamp objects instead of as system Date objects. So you will also need to update code expecting a Date to instead expect a Timestamp. For example:

// old:
let date: Date = documentSnapshot.get("created_at") as! Date
// new:
let timestamp: Timestamp = documentSnapshot.get("created_at") as! Timestamp
let date: Date = timestamp.dateValue()

Please audit all existing usages of Date when you enable the new behavior. In a future release, the behavior will be changed to the new behavior, so if you do not follow these steps, YOUR APP MAY BREAK.

dannypier avatar May 19 '18 18:05 dannypier

Valid point, @dannypier... Maybe I will find a better alternative... I will keep you updated, guys

alickbass avatar May 19 '18 20:05 alickbass

@alickbass Right now Firestore is crashing while using Date objects in the model, and I am also not very keen to be using FIRTimestamp in my model objects. It's not a dependency I'd like to have in my project as we might shift from Firestore in the future.

Edit: Firestore wasn't crashing because of the FIRTimestamp. Sorry, had a wrong call because of another Google product.

I took an attempt at supporting this. I realized the best way to do it is while encoding a Date object to convert it into FIRTimestamp with their initializer + (instancetype)timestampWithDate:(NSDate *)date; and while decoding if expecting a Date object taking the FIRTimestamp and doing timestamp.dateValue() and if expecting it as FIRTimestamp just return that

However, to achieve this CodableFirebase has to have access to FIRTimestamp in the project, that would mean we would need to add the Firestore pod into the project. I'm not sure how open you are to doing this.

serjooo avatar Aug 23 '18 18:08 serjooo

In general, I am okay with adding Firebase as a dependency and removing all the redundant protocols and just working with Firebase / Firestore values. If you guys are willing to contribute, please submit a PR and I would love to review. Unfortunately, I haven't had time lately to submit any code myself

alickbass avatar Sep 13 '18 15:09 alickbass

@alickbass I'll work on it this weekend. I was busy this past week. I'm going to try to do it without actually including Firebase as a dependency, if I am not able I'll just go ahead and add it.

serjooo avatar Sep 18 '18 18:09 serjooo

@serjooo tbh, I would like to add it as a dependency and remove all the weird protocols that we have.

alickbass avatar Sep 19 '18 08:09 alickbass

@alickbass What method do you see best fitting to add Firebase as a dependency? I stumbled upon this issue where things become a little tricky to add Firebase through Cocoapods

serjooo avatar Sep 20 '18 08:09 serjooo

Was this ever solved? @serjooo @alickbass

jimijon avatar Feb 19 '19 00:02 jimijon

@jimijon not yet. We need to add Firebase as a dependency of this project; however, I really had some hard time doing it and never had the time to research and give a shot again, but most probably I'll try to contribute again as I'm thinking of using CodableFirebase again for a future project of mine.

serjooo avatar Feb 19 '19 14:02 serjooo

@serjooo @alickbass any updates on this and/or is there any workaround? I had to update Firestore so I can use their new collection group query but keep running into the crash when decoding Date in the new version (Firebase 6.0.0, Firestore 1.3.0).

siyao1030 avatar May 20 '19 08:05 siyao1030

@alickbass I finally found sometime to work on this today and I included the FirebaseFirestore pod as a dependency to CodableFirebase and started working on the Encoding and Decoding. However, I realized Google are almost ready to merge in your implementation and some changes on to master via this PR https://github.com/firebase/firebase-ios-sdk/pull/2229

Do you think its still worth investing more time and doing the same implementation as that PR on CodableFirebase and merge it until they release?

Also something to note adding FirebaseFirestore stops support for macOS watchOS and tvOS because the Podspec lint errored as FirebaseFirestore itself doesn't have official support for them

serjooo avatar May 30 '19 13:05 serjooo

I have started working on that PR myself quite some time ago, however, due to change in work could not continue... I am not sure what is their roadmap and timeline is...

alickbass avatar May 31 '19 09:05 alickbass

Yes you are right it seems like they keep postponing the release and you can never be sure of what their timeline is. How about you submit a PR of your current work on a separate branch and we can work on it together?

serjooo avatar May 31 '19 09:05 serjooo

sorry, I meant the PR on Firebase itself 😂I haven't done anything here yet, so feel free to submit your ideas 😎

alickbass avatar Jun 01 '19 16:06 alickbass

let date: Date = timestamp.dateValue()

perfect one . it's woking for me. thank you so much for sharing

SidPatel12 avatar Jul 18 '19 06:07 SidPatel12

So, what happened with this ? I'm still dealing with

Expected to decode Date but found FIRTimestamp instead.

What do you guys suggest to solve this ? I have a Date object in my model

danismatiazGL avatar Aug 18 '19 02:08 danismatiazGL

So, what happened with this ? I'm still dealing with

Expected to decode Date but found FIRTimestamp instead.

What do you guys suggest to solve this ? I have a Date object in my model } **

let timestamp: Timestamp = dicDocument["Date"] as! Timestamp let timeStmp = timestamp.dateValue() msg.date = timeStmp

** i have taken date variable and its type is Date() in model. i have stored date as timeStamp in firestore.

SidPatel12 avatar Aug 19 '19 05:08 SidPatel12

@alickbass seems like Google merged Codable support into master https://github.com/firebase/firebase-ios-sdk/pull/3198 didn't check the implementation or test it out myself. Will do that and close this issue accordingly

serjooo avatar Aug 19 '19 09:08 serjooo

So, what happened with this ? I'm still dealing with Expected to decode Date but found FIRTimestamp instead. What do you guys suggest to solve this ? I have a Date object in my model } **

let timestamp: Timestamp = dicDocument["Date"] as! Timestamp let timeStmp = timestamp.dateValue() msg.date = timeStmp

** i have taken date variable and its type is Date() in model. i have stored date as timeStamp in firestore.

How did you end up doing this?

Rspoon3 avatar Jan 24 '20 06:01 Rspoon3

@alickbass seems like Google merged Codable support into master firebase/firebase-ios-sdk#3198 didn't check the implementation or test it out myself. Will do that and close this issue accordingly

How does it compare to this library?

Rspoon3 avatar Jan 24 '20 06:01 Rspoon3

I'm running into this On my model I have these values:

    var created: Date?
    var updated: Date?

Firestore is returning them in this format: "updated": <FIRTimestamp: seconds=1617128658 nanoseconds=859000000>

My understanding is that I could use this library to decode from Timestamp directly to date like this:

let model = try FirestoreDecoder().decode(Model.self, from: item.data())

Unfortunately it throws the error: typeMismatch(Foundation.Date, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "created", intValue: nil)], debugDescription: "Expected to decode Date but found FIRTimestamp instead.", underlyingError: nil))

Does anyone know how to solve this? I'm pulling my hair out trying to avoid writing a custom initializer or even a custom model for the one area of the app where this model gets loaded up from the Firestore.

bryan1anderson avatar Apr 01 '21 21:04 bryan1anderson