Code Monkey home page Code Monkey logo

Comments (18)

Kronhyx avatar Kronhyx commented on May 28, 2024 3

any update on this?

from fireorm.

nietzscheson avatar nietzscheson commented on May 28, 2024 2

@wovalle I think that @lucasdidur is doing reference to: https://firebase.google.com/docs/firestore/data-model#references for me it's more easy can related documents with references that as subcollections.

from fireorm.

nietzscheson avatar nietzscheson commented on May 28, 2024 2

@Kronhyx I found this similar ORM

from fireorm.

wovalle avatar wovalle commented on May 28, 2024 2

Thanks! Didn't know about firestorm (and I'm mad because that name is awesome :D). I updated my roadmap (#1) to increase the compatibility with raw firestore documents. For now I'll close this issue.

from fireorm.

LuisDev99 avatar LuisDev99 commented on May 28, 2024 2

It could be an alternative. Right now, I'm looking at what Firebase Firestorm does to create a document reference when creating a new document.

They have this:

export default class Post extends Entity {
  @documentRef({
    name: 'author',
    entity: Author, // we must define the entity class due to limitations in Typescript's reflection capabilities. Progress should be made on this issue in future releases.
  })
  author!: IDocumentRef<Author>;
  ...
}

So I'll look if they have a way of creating a document reference inside the create method. If they do, I'll check out the code and share it with you to give more ideas

from fireorm.

wovalle avatar wovalle commented on May 28, 2024 1

That API looks nice indeed!

Some questions that are still unanswered:

In your example artist was declared as Artist but in the create, artist is being set by the reference path (string). What if we pass an Artist object instead? It needs to be an Artist in the model declaration to allow typescript completion.

It would look like this:

const artist = new Artist()
artist.id = 'new-artist'
artist.name = "New Artist"

getRepository(Band).create({ 
   id: 'fireorm rocks!',
   artist,
});

What would happen if you try to save an Album with a new artist (aka still not saved in firestore)?

  • Should fireorm do it for you (inside a transaction)?
  • Should fireorm throw an error
  • Should fireorm provide a helper function like setReference and then determine if it should be created or not?
const artist = new Artist()
artist.id = 'new-artist'
artist.name = "New Artist"

getRepository(Band).create({ 
   id: 'fireorm rocks!',
   artist: setReference(artist),
});

from fireorm.

wovalle avatar wovalle commented on May 28, 2024

I understand the problem but what is what you're trying to achieve? If you want Produtor to be a subcollection of ProdutorDadosAdicionais, you should remove the @Collection decorator from Produtor and follow the subcollection example.

If what you want is to stablish a 1:1 relationship between your entities I would start removing the @Collection decorator.

Apart from that, I see that there might be a bug with the deserialization/serialization of the firestore entities when the values are class instances. I could recommend adding produtorId and produtorNome as properties in ProdutorDadosAdicionais while this is fixed

from fireorm.

Kronhyx avatar Kronhyx commented on May 28, 2024

@lucasdidur @wovalle @nietzscheson
Have you been able to find any solution for this?

from fireorm.

LuisDev99 avatar LuisDev99 commented on May 28, 2024

Would you like to consider re-opening this issue @wovalle ?

from fireorm.

wovalle avatar wovalle commented on May 28, 2024

Here's some documentation about searching by reference: https://fireorm.js.org/#/Read_Data?id=search-by-document-reference

What other do you guys think are missing?

from fireorm.

LuisDev99 avatar LuisDev99 commented on May 28, 2024

@wovalle thank you!

It would be really great if we could this:

@Collection()
class Artist { 
  id: string;
  name: string;
  // some other useful props
}

@Collection()
class Band {
  id: string;
  
  @DocumentReference()
  artist: Artist;
}

Then this:

getRepository(Band).create( { 
    id: 'fireorm rocks!',
    artist: '/artists/wovalle'   // Making a reference to a Collection ```artist``` to a document ```wovalle```
});

That way, when we create a new band document, artist will appear as a document reference data type in firestore, giving us the opportunity to do this:

getRepository(Band).find().forEach((band) => console.log(band.artist.name));

As you can see, it is really easy to access the artist of a particular band without having the need to go fetch the artist or making a subcollection. Let me know what you think and I will be happy to help you

from fireorm.

LuisDev99 avatar LuisDev99 commented on May 28, 2024

In your example artist was declared as Artist but in the create, artist is being set by the reference path (string). What if we pass an Artist object instead? It needs to be an Artist in the model declaration to allow typescript completion.

Yes, I set the artist in the create method as a string. By adding the @DocumentReference() decorator, the property Artist can be assign either an object or a string that points to its desired reference (I forgot to put Artist | string, read below to know the reason)

What would happen if you try to save an Album with a new artist (aka still not saved in firestore)?

Should fireorm do it for you (inside a transaction)?
Should fireorm throw an error
Should fireorm provide a helper function like setReference and then determine if it should be created or not?

I believe that fireorm should just let you or throw an error at best given that firestore allows you to set a reference to a non-existent document when the reference is of type string. It should be the developer's job to ensure he's doing a valid reference IMO.

The reason I assigned the artist a string inside the create method

getRepository(Band).create( { 
    id: 'fireorm rocks!',
    artist: '/artists/wovalle'   // Making a reference to a Collection ```artist``` to a document ```wovalle```
});

is to be able to check to see if the artist property is of type string or object.

  • If it's of type string, we let the create method do the insert normally and nothing more
  • If it's of type object, it would be nice to create the Artist first and then, assign the reference to the newly created artist inside a single transaction.

This way, we let the create method accept both of this options. For example, like this:

/* Create example with a string */ 
 getRepository(Band).create({ 
    id: 'fireorm rocks!',
    artist: '/artists/wovalle'   // I'm a string, the create method should do the insert normally! 
                                 // (And I'll still be able to appear as a firestore document reference data type)
});
 
/* Create example with an object */
 getRepository(Band).create({ 
    id: 'fireorm rocks!',
    artist: { 
       id: 'new artist from a newly created band',
       name: 'cisco'
    }      // In here, I'm an artist object, maybe fireorm can create me first and then create the band and 
           // automatically reference me! (And still be able to appear as a firestore document reference data type)
});

Let me know what you think 🙏🏻

from fireorm.

wovalle avatar wovalle commented on May 28, 2024

Instead of forcing the user to declare all of the references as T | string it'll be a better idea to provide a generic type that accepts T and resolves to T | string (something like: Reference<Artist>)

@Collection()
class Band {
  id: string;
  
  @DocumentReference()
  artist: Reference<Artist>;
}

Given that the reference field must be decorated with DocumentReference, in runtime we save it if is T or just save the reference if is string. Is there a way to validate that the reference string is a valid path?

And one problem I find here is that we're using plain objects as the parameter for create where fireorm receives T. I guess something has to be done to receive T or something that looks like T (A extends T?)

Another problem is that as of today, there's no easy way to get the path (ref?) of a fireorm entity. To achive this something must be done. Maybe adding a getRef/getPath function in each entity might solve this. What would be better? Is ref always the path to the document? 🤔

from fireorm.

LuisDev99 avatar LuisDev99 commented on May 28, 2024
@DocumentReference()
  artist: Reference<Artist>;

Looks really great! Couldn't agree more.

Is there a way to validate that the reference string is a valid path?

This is what the Google API NodeJS Firestore repository does to validate a path:

export function validateResourcePath(
  arg: string | number,
  resourcePath: string
): void {
  if (typeof resourcePath !== 'string' || resourcePath === '') {
    throw new Error(
      `${invalidArgumentMessage(
        arg,
        'resource path'
      )} Path must be a non-empty string.`
    );
  }

  if (resourcePath.indexOf('//') >= 0) {
    throw new Error(
      `${invalidArgumentMessage(
        arg,
        'resource path'
      )} Paths must not contain //.`
    );
  }

They just check if the path is a valid string and does not contains any double slash.

Another problem is that as of today, there's no easy way to get the path (ref?) of a fireorm entity. To achive this something must be done. Maybe adding a getRef/getPath function in each entity might solve this. What would be better?

The getPath sounds great! I guess the implementation would go something like this:

return this.className(?) + '/' + this.id; // I actually don't know how you take the classname (or the collection name if overriden) of the entity lol

Is ref always the path to the document?

Yes!

This link might be helpful as well

from fireorm.

wovalle avatar wovalle commented on May 28, 2024

About the validation: That's easy then 🙌 , In the future I imagine adding an option to prevent adding a relationship that doesn't exist yet.

About getPath: every repository has access to the path this.path. Whenever fireorm constructs a class (via creating an object or doing a query) extractTFromDocSnap is called, so to append the path to each document would be as easy as passing the path there (with a readonly variable name close to fireorm_internal_path and adding the getPath method in the abstract repository that will return it.

from fireorm.

wovalle avatar wovalle commented on May 28, 2024

Did the initial work to support references in #238! Still a long way to go though!

Check this test

I found out that my initial Reference<Artist> suggestion won't work. I'd like to be able to do something like band.reference.id which is not possible if reference is declared as Reference<Artist>.

from fireorm.

LuisDev99 avatar LuisDev99 commented on May 28, 2024

Awesome!

expect((savedSW.relatedBand as Band).id).toEqual(nm.id);

You mean from this right (the casting)? I really don't know a clean solution for that

from fireorm.

wovalle avatar wovalle commented on May 28, 2024

Yeah I'll have to rethink the api. The only thing that occurs to me at the moment is to leave it as T and add a second parameter to create to pass the paths, but that'll be more challenging.

Something like:

/* Create example with an object */
getRepository(Band).create({
  id: 'fireorm rocks!',
  artist: {
    id: 'new artist from a newly created band',
    name: 'cisco',
  },
});

getRepository(Band).create(
  {
    id: 'fireorm rocks!',
  },
  { refs: { artist: '/artists/wovalle' } }
);

from fireorm.

Related Issues (20)

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.