-
Notifications
You must be signed in to change notification settings - Fork 65
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add out-of-the-box date support #4
Comments
Proposed SolutionPass a
Use CaseYou have a document with this kind of format: // users/one
{
createdAt: Date
} If you do this: const { data } = useDocument('users/one')
let createdAt: Date
if (data) {
// 🚨 error! must turn firestore date into JS date object
createdAt = data.createdAt
} You get an error. We must run const { data } = useDocument('users/one')
let createdAt: Date
if (data) {
// ✅ works!
createdAt = data.createdAt.toDate()
} APIIt would be nice if this parsing worked for you under-the-hood, using the Taking the previous example, where we have a const { data } = useDocument('users/one', {
parseDates: ['createdAt'] // nested fields would look like "user.createdAt"
})
let createdAt: Date
if (data) {
// ✅ works!
createdAt = data.createdAt
} No more need for Function APIThis same field could also accept a function (which I would memoize under the hood) that lets you parse a document itself. A bit less magical, but maybe you want more control. The api would look like this: const { data } = useDocument('users/one', {
parseDates: (doc) => ({ ...doc, createdAt: doc.createdAt.toDate() })
})
let createdAt: Date
if (data) {
// ✅ works!
createdAt = data.createdAt
} RoadblocksThe roadblocks to the current implementation are mostly TypeScript suggestions. Since we give Here is how I currently work around this in my apps: import * as firebase from 'firebase'
// If S = true, it's a server date. If S = false, it's a JS Date
type ServerDate<S extends boolean = false> = S extends true ? firebase.firestore.Timestamp : Date
// Create document TS schema
type Doc<IsServer extends boolean = false> = {
createdAt: ServerDate<IsServer>
}
type ServerDoc = Doc<true>
type ParsedDoc = Doc // implicit false
const useUser = () => {
const { data, ...rest } = useDocument<ServerDoc>('users/one')
// function that takes in a doc and returns the parsed doc
const parseForRender = (doc: ServerDoc): ParsedDoc => {
return {
...doc,
createdAt: doc.createdAt.toDate()
}
}
return { data: data && parseForRender(data), ...rest }
} I think a good solution is just to have the Example: import * as firebase from 'firebase'
// If S = true, it's a server date. If S = false, it's a JS Date
type ServerDate<S extends boolean = false> = S extends true ? firebase.firestore.Timestamp : Date
// Create document TS schema
type Doc<IsServer extends boolean = false> = {
createdAt: ServerDate<IsServer>
}
type ServerDoc = Doc<true>
type ParsedDoc = Doc // implicit false
// pass the normal *parsed doc* field here
const { data } = useDocument<ParsedDoc>('users/one', {
// we *explicitly* tell TS that the argument is a ServerDoc
// useDocument will enforce that it returns a ParsedDoc type
parseDates: (doc: ServerDoc) => ({ ...doc, createdAt: doc.createdAt.toDate() })
}) The only downside to the above case is that I might need to @ts-ignore a little bit in the library, but it's not the end of the world. CodeThe lib could have a import { get, set } from 'lodash'
type ParseDatesOption<Data> = string[] | ((doc: unknown) => Data)
function dateParser<Data>(doc: Data, parseDates: ParseDatesOptions<Data>) {
let finalDoc = { ...doc }
if (Array.isArray(parseDates)) {
parseDates.forEach((dateField) => {
const unparsedDate = get(dateField)
if (unparsedDate) {
const parsedDate = unparsedDate.toDate && unparsedDate.toDate()
if (parsedDate) {
set(finalDoc, dateField, parsedDate)
}
}
})
} else if (typeof parseDates === 'function') {
finalDoc = parseDates(doc)
}
return finalDoc
} |
Added in APItype Data = {
createdAt: Date
lastUpdated: {
date: Date
}
}
const { data } = useDocument<Data>('users/fernando', {
parseDates: ['createdAt', 'lastUpdated.date']
})
let createdAt: Date
let updatedAt: Date
if (data) {
createdAt = data.createdAt // ✅ JS date!
updatedAt = data.lastUpdated.date // ✅ JS date!
} I went with the array of object key strings as the API. No function. |
Will close once I add an example to the readme. |
hi how are you! .. i can t compare dates in where field ..setWhere([["fecha", ">", data.fechaDesde] |
|
.toDate()
by recursively checking an object for any server dates and converting them intoDate
objects.serverTimestamp
field (I forget what the field called, this relates toonSnapshot
subscriptions creating pseudo timestamps before the local stuff hits the backend.)The text was updated successfully, but these errors were encountered: