Git Product home page Git Product logo

firelordjs's Introduction

Hi there, I'm tylim!, a Typescript Zombie ๐ŸงŸ๐Ÿ‘‹

tylim88's github stats

Are you curious about creating an Odd Number Type?

Or how to create a deep, type-safe database wrapper like FireSage and Firelord?

You can find all these knowledge pieces and more in my articles on various TypeScript quirks, tips, and techniques.

firelordjs's People

Contributors

dependabot[bot] avatar lgtm-migrator avatar tylim88 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

firelordjs's Issues

What is the right way to declare type for data object, passed to updateDoc?

Hello, firstly, thank you for amazing library that makes everything easier!!!

I have some trouble:

I need to implement a helper function, that makes it possible to not add some required parameters in every call of updateDoc/batch.update, and I'm unable to figure out, what type of FirestoreUpdateParams.data parameter should be to pass the typescript validation, and, more importantly, throw errors, if I'm passing wrong data to this helper function.

Here is the code:

import { DocumentData } from 'firebase/firestore';
import { serverTimestamp, updateDoc, DocumentReference } from 'firelordjs';

import type { WriteBatch } from 'firelordjs/dist/types';
import { ChatsMetaType } from '~/models/firestore/chat';

import store from '~/store';
import type { UpdateAction } from '~/types/global';

const autoLog = true;

const timestamp = serverTimestamp();

type FirestoreUpdateParams = {
  batch?: WriteBatch;
  ref: DocumentReference<ChatsMetaType>;
  data: __HERE__;
  action: string;
  params?: DocumentData;
  log?: boolean;
};

export function $firestoreUpdate({
  batch,
  ref,
  data,
  action,
  params = {},
  log = autoLog,
}: FirestoreUpdateParams): Promise<void> {
  const mixin = {
    update_action: {
      type: action,
      params,
      timestamp,
    } as UpdateAction,
    updated_by_uuid: store.getters['auth/user'].uid as string,
    updated_at: timestamp,
    updated_by_platform: 'web' as string,
  };

  const mixedData = {
    ...data,
    ...mixin,
  };

  if (batch) {
    if (log) {
      console.log(
        '$firestoreUpdate in batch',
        ref.path,
        action,
        params,
        mixedData,
      );
    }
    batch.update(ref, mixedData);
    return Promise.resolve();
  }

  if (log) {
    console.log('$firestoreUpdate', ref.path, action, params, mixedData);
  }
  return updateDoc(ref, mixedData);
}

Expecting to use it like this:

firestoreUpdate({
  ref: ...,
  data:  {
     name: 'string', // Ok, no error, name is defined in MetaType
     name: 0,  // Error: type must be string
     unknownProp: 'value', // Error: no such property
  },
  ....
});

But this type would be also useful when creating data object in few places step by step

const dataObject: __HERE__ = {};

dataObject.name = 'string'; // No error 
dataObject.name = 0; // Error, must be string
dataObject.unknownProp = 'value'; // Error, unknown prop

// ...

firestoreUpdate({
  ref: ...,
  data: dataObject,
  ....
});

[ENHANCEMENT] Abstract MetaType

Hello again. After resolving issue #89 I've got another one)

All collections in my Firestore have few required fields, that have same types, so it would be great to have some kind of AbstractMetaType, where I can put those fields, and then extend that type by the specific MetaType for the specific collection.
It will be useful again in those helper functions, described in #89, because for now they are stick to specific MetaType, so when I want to use that function to update document from another collection, i have to change $firestoreUpdate helper's signature, which looks inconvenient.

Here is an approximate example for what do i mean:

export type FirestoreEntityData = {
  _uid: string;
  // STATUS
  status: EntityStatus;
  //
  update_action: UpdateAction;
  // TIMESTAMPS
  created_at: ServerTimestamp;
  creator_uuid: string;
  created_by_platform: string;
  //
  updated_at: ServerTimestamp;
  updated_by_uuid: string;
  updated_by_platform: string;
  //
  deleted_at: ServerTimestamp | null;
  deleted_by_uuid: string | null;
  deleted_by_platform: string | null;
};

export type AbstractEntityMetaType = AbstractMetaTypeCreator<FirestoreEntityData>; // No collection name, id type and parent

// Then creating specific MetaType

export type FirestoreChatData = {
  name: string;
};

export type ChatMetaType = MetaTypeCreatorFromAbstract<AbstractEntityMetaType, FirestoreChatData, 'Chats'>;

export type FirestoreUserData = {
  first_name: string;
  last_name: string;
};

export type UserMetaType = MetaTypeCreatorFromAbstract<AbstractEntityMetaType, FirestoreUserData, 'Users'>;

This extension may be done just by making

export type FirestoreChatData = {
  name: string;
} & FirestoreEntityData;

But main idea is to make AbstractEntityMetaType compatible with any other MetaType, extended from it, when working with only fields, that are present in FirestoreEntityData

So then we can use it like this:

const timestamp = serverTimestamp();

type FirestoreUpdateParams<
  T extends AbstractEntityMetaType,
  K extends Partial<T['write']>
> = {
  batch?: WriteBatch;
  ref: DocumentReference<T>;
  data: K;
  action: string;
  params?: DocumentData;
};

export function $firestoreUpdate<
  T extends AbstractEntityMetaType,
  K extends Partial<T['write']>,
>({
  batch,
  ref,
  data,
  action,
  params = {},
}: FirestoreUpdateParams<T, K>): Promise<void> {
  const mixin: K = {
    update_action: {
      type: action,
      params,
      timestamp,
    },
    updated_by_uuid: store.getters['auth/user'].uid,
    updated_at: timestamp,
    updated_by_platform: 'web' ,
  };

  const mixedData = {
    ...data,
    ...mixin,
  };

  if (batch) {
    batch.update(ref, mixedData);
    return Promise.resolve();
  }

  // No error, since all props, added in mixin are present in AbstractEntityType['Write']
  return updateDoc(ref, mixedData);
}

// And usage

$firestoreUpdate({
  ref: ChatRef,
  data: { name: 'Test' },
});
//
$firestoreUpdate({
  ref: UserRef,
  data: {  first_name: 'Vasya Pupkin' },
});

Maybe it's already possible, and I'm missing something.
Also I'm quite new to typescript, so maybe have some mistakes in my assumptions

[BUG] Types break when getting all documents in a collection without query

  1. Version: latest
  2. Meta Type =
    { title: string; type: 'object'; properties: { [name: string]: 'string' | 'boolean' | 'integer'; }; };
  3. Trying to run (await getDocs(this.db.collection())).docs
  4. What I expect to get:
    When using (await getDocs(query(this.db.collection))).docs
    The docs getter is of type: get QuerySnapshot<MetaTypeCreator<Schema, "schema", string, null, { allFieldsPossiblyReadAsUndefined: false; banNull: false; }>>.docs(): QueryDocumentSnapshot<MetaTypeCreator<Schema, "schema", string, null, {allFieldsPossiblyReadAsUndefined: false, banNull: false}>>[]
  5. What Im Actually Getting:
    The type of docs getter is:
    get QuerySnapshot<MetaType>.docs(): QueryDocumentSnapshot<MetaType>[]

TLDR:
getDocs(query(this.db.collection())) works
getDocs(this.db.collection()) doesn't
Even tho docs state it should: https://firebase.google.com/docs/firestore/query-data/get-data#get_all_documents_in_a_collection

Uncaught FirebaseError: Expected first argument to collection() to be a CollectionReference, a DocumentReference or FirebaseFirestore[BUG] title

Using the latest version with the example code, I'm seeing this:

image

image

narrowed it down to this minified code in the firebase module

image

which I'm pretty sure this this

image

I think something weird is going on with the classes, and the firestore instance that firelord lib ends up with isn't registering as the same class that the firestore lib has.

Have this library been used on the frontend before?

:fire::fire::fire::fire:

No idea how else to reach out to you but this library looks awesome. I'm currently building a small POC and will be using firelord in that.

If you have a product roadmap or suggestions for contributions - I'd love to help where I can. RTFM - apologies

Also side Q - any suggestions on typescript books or resources? Your knowledge is incredible

Pagination

Hey, is it possible to paginate with the latest received item?

From firestore docs:

import { collection, query, orderBy, startAfter, limit, getDocs } from "firebase/firestore";  

// Query the first page of docs
const first = query(collection(db, "cities"), orderBy("population"), limit(25));
const documentSnapshots = await getDocs(first);

// Get the last visible document
const lastVisible = documentSnapshots.docs[documentSnapshots.docs.length-1];
console.log("last", lastVisible);

// Construct a new query starting at this document,
// get the next 25 cities.
const next = query(collection(db, "cities"),
    orderBy("population"),
    startAfter(lastVisible),
    limit(25));

Not a issue, but a question about your project (comparating it to another solution)

Hi,
Here is quick hack to have types with firebase:
https://javascript.plainenglish.io/using-firestore-with-typescript-in-the-v9-sdk-cf36851bb099
https://github.com/JamieCurnow/firebase-v9-typescript-example

Could you tell me, very shortly, what does your library FirelordJS offers more ? Because, well, I am pretty sure I did something wrong, but I was trying your lib with sveltekit and ts. And I have encountered issues (unfortunately, I dont remember exactly what it was...), and at the end, comparated to the little hack mentioned above, I hesitate to use your lib, because first, I will depends on a non official lib, FirelordJS, instead the official one Firebase-firestore... And then, I have heard that it is not easy to SSR transform the firestore sdk code in sveltekit... so using your lib could also be more difficult...

That is why, I am mitigated to use your lib, could you argue something to help to do the good decision ?
Tks

Node module resolution issue

Hi there! Thanks for the excellent library.

It's not a must-have, but it would be cool if you could build with target set to CommonJS, as users of frameworks like Nextjs (<v13) will run into Nodejs module resolution issues. It can be solved with next-transpile-modules, but it can take some time to unearth that solution - I almost gave up.

Thanks again,
Steven

[BUG] Type instantiation is excessively deep and possibly infinite when creating MetaType

Hey @tylim88, hope you're doing well!
I've got some weird error with the same code, that worked before and also works with firelord package

  1. Version?
    v2.5.13
  2. What is the Meta Type?
import type {
  MetaTypeCreator,
  Timestamp,
} from 'firelordjs'; // If use firelord instead of firelordjs - no error

export type FileData = {
  _uid: string;
  original_name: string;
  size: number;
  last_modified: Timestamp; // if comment this - no error
};

export type FirestoreDummyType = {
  _uid: string;
  avatar: FileData;
};

// ERROR: TS2589: Type instantiation is excessively deep and possibly infinite.
export type DummyMetaType = MetaTypeCreator<FirestoreDummyType, 'Dummy'>;
  1. What operations are you trying to run?
    Create MetaType with nested object, that have Timestamp in props
  2. What do you expect?
    No error should be reported. And same code works fine with firelord or older version of firelordjs (v2.3.7 for example)
  3. What do you see?
    ERROR when creating MetaType: TS2589: Type instantiation is excessively deep and possibly infinite.

Meta Type with union base type

Hi,
first of all, this library is really nice to work with and it has helped me a lot. Now to my problem.
I try to create a Meta Type that can be of two different base types that have some properties in common, here my Base Types with Meta Type:

export type ShoppingListItemType = MetaTypeCreator<{
  name: string, // GeneralItem
  quantity: string,
  checked: boolean,
  discounts: Discount[],
} | {
  name: string,  // SpecialItem
  quantity: string,
  checked: boolean,
  category: string,
  discount: Discount | PossiblyReadAsUndefined,
  added: Date | Timestamp | FieldValue,
}, 'items', string, ShoppingListsType>

Then when I want to create a document like this.

const ref = getFirelord<ShoppingListItemType>()(`users/${uid}/shoppingLists/${shoppingListId}/items`).doc(itemId.toString());

await setDoc(ref, item); // Error at item

When I use auto completion to check which properties are available, it shows me only name, quantity and checked.

Here you can see the error I'm getting:

Argument of type 'ShoppingListItem' is not assignable to parameter of type 'HandleUnknownMember<{ name: string; quantity: string; checked: boolean; }, GeneralItem> | HandleUnknownMember<{ name: string; quantity: string; checked: boolean; }, SpecialItem>'.
  Type 'GeneralItem' is not assignable to type 'HandleUnknownMember<{ name: string; quantity: string; checked: boolean; }, GeneralItem> | HandleUnknownMember<{ name: string; quantity: string; checked: boolean; }, SpecialItem>'.
    Type 'GeneralItem' is not assignable to type 'HandleUnknownMember<{ name: string; quantity: string; checked: boolean; }, GeneralItem>'.
      Type 'GeneralItem' is not assignable to type '{ discounts: "Error: Please remove the unknown member ( discounts )"; }'.
        Types of property 'discounts' are incompatible.
          Type 'Discount[]' is not assignable to type '"Error: Please remove the unknown member ( discounts )"'.ts(2345)

I will be thankfull for any help.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.