elersong / fireorm24

ORM for Firebase Firestore 🔥 updated for 2024
MIT License
1 stars 0 forks source link

Compatibility Issue with Timestamps in firebase-admin SDK v11.11.1 #40

Open elersong opened 3 months ago

elersong commented 3 months ago

Description

The update method of BaseFirestoreRepository in Fireorm is not handling Timestamp objects created with the latest firebase-admin SDK v11.11.1. The Timestamp objects from firebase-admin v11.11.1 are not recognized as valid Firestore documents, whereas Timestamp objects from @google-cloud/firestore still work as expected.

Steps to Reproduce

  1. Create an entity with a timestamp field.
  2. Use firebase-admin SDK v11.11.1 to update the entity's timestamp field.
  3. Attempt to update the entity in Firestore using Fireorm.
  4. Observe the error related to the Timestamp object.

Expected Behavior

Fireorm should be able to handle Timestamp objects from the latest firebase-admin SDK without errors.

Actual Behavior

An error occurs, indicating that the Timestamp object is not a valid Firestore document.

Acceptance Criteria

Additional Context

Proposed API Changes

  1. Update Timestamp Handling:

    • Modify the update method to handle Timestamp objects from both firebase-admin and @google-cloud/firestore.
    import { firestore } from 'firebase-admin';
    import { Timestamp as GCTimestamp } from '@google-cloud/firestore';
    
    class BaseFirestoreRepository<T> {
     async update(item: T): Promise<T> {
       const plainObject = this.convertToPlainObject(item);
       await this.firestoreColRef.doc(item.id).update(plainObject);
       return item;
     }
    
     private convertToPlainObject(item: T): any {
       const obj = JSON.parse(JSON.stringify(item));
       for (const key in obj) {
         if (obj[key] instanceof firestore.Timestamp || obj[key] instanceof GCTimestamp) {
           obj[key] = obj[key].toDate();
         }
       }
       return obj;
     }
    }
  2. Unit Tests:

    • Add unit tests to validate the handling of Timestamp objects from different SDKs.
    import { firestore } from 'firebase-admin';
    import { Timestamp as GCTimestamp } from '@google-cloud/firestore';
    
    test('should handle firebase-admin Timestamp', async () => {
     const repo = getRepository(MyEntity);
     const entity = new MyEntity();
     entity.id = 'entity1';
     entity.timestamp = firestore.Timestamp.fromDate(new Date());
    
     await expect(repo.update(entity)).resolves.not.toThrow();
    });
    
    test('should handle @google-cloud/firestore Timestamp', async () => {
     const repo = getRepository(MyEntity);
     const entity = new MyEntity();
     entity.id = 'entity1';
     entity.timestamp = GCTimestamp.fromDate(new Date());
    
     await expect(repo.update(entity)).resolves.not.toThrow();
    });

Example Implementation

import { Collection, getRepository } from 'fireorm';
import { firestore } from 'firebase-admin';
import { Timestamp as GCTimestamp } from '@google-cloud/firestore';

@Collection()
class MyEntity {
  id: string;
  timestamp: Date;
}

const repo = getRepository(MyEntity);

async function updateEntityWithAdminTimestamp() {
  const entity = await repo.findById('entity1');
  entity.timestamp = firestore.Timestamp.fromDate(new Date());
  await repo.update(entity);
}

async function updateEntityWithGCTimestamp() {
  const entity = await repo.findById('entity1');
  entity.timestamp = GCTimestamp.fromDate(new Date());
  await repo.update(entity);
}

updateEntityWithAdminTimestamp();
updateEntityWithGCTimestamp();

Original Issue

elersong commented 3 months ago

Potentially connected with #33 and #31