bijoutrouvaille / fireward

A concise and readable language for Firestore security rules, similar to Firebase Bolt.
MIT License
238 stars 4 forks source link

String literal output #15

Closed henrymoulton closed 4 years ago

henrymoulton commented 4 years ago

Hi, thanks for the release of string literals!

When my type is:

type UserJourneyStatus = "onboarding" | "pending" | "joined"

type UserDataForAdminDoc = {
  uid: string,
  createdAt: timestamp,
  updatedAt: timestamp,
  userJourneyStatus: UserJourneyStatus,
}

type UserStatusDoc = {
  userJourneyStatus: UserJourneyStatus
}

My terminal output is:

type `UserJourneyStatus` is missing definition
  on line 23, column 25
type `UserJourneyStatus` is missing definition
  on line 23, column 25`

My rules generated are:

function is____UserStatusDoc(data, prev) {
      return data.keys().hasAll(['userJourneyStatus'])
      && data.size() >= 1 && data.size() <= 1
      && data.keys().hasOnly(['userJourneyStatus'])
      && (prev==null && is____UserJourneyStatus(data.userJourneyStatus, null) || is____UserJourneyStatus(data.userJourneyStatus, prev));
    }

The idea here is I want to be able to specify types I can share across documents where data is duplicated, which is quite common in Firestore, in this example UserDataForAdminDoc is readable and writable by Admins, and any change is copied over to UserStatusDoc with a Firebase function, allowing the user to be able to read their status, but not change it.

bijoutrouvaille commented 4 years ago

@henrymoulton thanks for the report. I'm unable to reproduce. Can you please make sure that your Fireward version is 1.2.3 by running fireward --version?

henrymoulton commented 4 years ago

Was my fault, was running an old version in a different shell!

bijoutrouvaille commented 4 years ago

@henrymoulton no problem. At this stage, it's much better for the project to have users reporting false positives than not at all.

henrymoulton commented 4 years ago

Thanks, I wondered if you had any thoughts on statically typing the firestore().collection and .doc() references based on fireward types. At the moment I've created some string enums separately but it's something in the back of my mind when doing data fetching. GraphQL knows which queries are possible via a schema... do you think something similar is possible with Firestore?

bijoutrouvaille commented 4 years ago

I've tried building elaborate systems for this in the past, but they all turned out to be overly complex and not very useful. Maybe 2019 improvements in TS would have made it much easier, but I am too skeptical to explore.

The approach I would recommend today is more manual and straight forward. You can create a client object, similar to one you might make for a regular REST API, and it would provide typed results. Something like this:

export const firestoreClient = {
   watchUser: (userId: string, callback: (user?: User)=>void) => 
     firestore.collection('users').doc(userId).onSnapshot(doc=>callback(doc.data()))
}