Skip to content
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

Assign values generated or calculated by a query ​​to an entity #40

Closed
ghost opened this issue Apr 8, 2019 · 9 comments
Closed
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@ghost
Copy link

ghost commented Apr 8, 2019

I'm not sure if this feature is out of ambit of a ORM. Feel free of close the issue directly, if so.

I have a entity:

@Entity({ collection: "location" })
export class LocationModel implements EntityLocation {
    @PrimaryKey()
    public _id!: ObjectId;

    @Property()
    public geometry!: EntityGeometry;

    @ManyToOne({ entity: () => BusinessModel })
    public business!: BusinessModel;

    public distance?: number;
}

export interface LocationModel extends IEntity<string> { }

And a query, MongoDB aggregation, that create a new value calculated (distance):

public async findNear(coordinates: number[]): Promise<LocationModel[]> {
    const entities: EntityLocation[] = await this.locationRepository.aggregate([
        {
            $geoNear: {
                distanceField: "distance",
                distanceMultiplier: 0.001,
                near: { coordinates, type: "Point" },
                spherical: true,
            },
        },
    ]);

    return entities.map((entity) => this.locationRepository.create(entity));
}

When converting the query result to entity, the value "distance" is ignored and I have to handle it manually. Can be possible implement something to handle it automatically, something like:

@Entity({ collection: "location" })
export class LocationModel implements EntityLocation {
    @PrimaryKey()
    public _id!: ObjectId;

    @Property()
    public geometry!: EntityGeometry;

    @ManyToOne({ entity: () => BusinessModel })
    public business!: BusinessModel;

    @Property({ persist: false })
    public distance?: number;
}

export interface LocationModel extends IEntity<string> { }
@B4nan
Copy link
Member

B4nan commented Apr 8, 2019

EntityManager.create() currently ignores properties that are not marked via decorators. You could create reference instead and use assign to include them:

return entities.map((data) => {
  const entity = this.locationRepository.getReference(data._id);
  entity.assign(data);
  return entity;
});

I will add bool parameter to create method so you can achieve it via single command, it makes sense to allow this.

@B4nan B4nan self-assigned this Apr 8, 2019
@B4nan B4nan added this to the 2.2 milestone Apr 8, 2019
@B4nan B4nan added the enhancement New feature or request label Apr 8, 2019
@B4nan
Copy link
Member

B4nan commented Apr 8, 2019

Or do you think its better to implement @Property({ persist: false })? Should be pretty easy.

It might be better as you could whitelist properties instead of allowing anything via one boolean.

@ghost
Copy link
Author

ghost commented Apr 8, 2019

I am sure you have more experience with ORMs. If you see some advantage to my proposition, perfect I will use it, else I don't want add maintenance complexity with features used only by me.

With the information of your previous response I can do a generic function to solve this, and can be enougth:

public static toModel<T>(entities: BaseEntity[], repository: EntityRepository<IEntityType<T>>): Array<IEntityType<T>> {
    return entities.map((entity) => {
        const model: IEntityType<T> = repository.getReference(entity.id);

        model.assign(entity);

        return model;
    });
}

@ghost
Copy link
Author

ghost commented Apr 9, 2019

Or maybe simply if `assign()´ return the entity, so that it can be done:

return entities.map((entity) => this.locationRepository.getReference(entity.id).assign(entity));

instead of:

return entities.map((entity) => {
    const location: LocationModel = this.locationRepository.getReference(entity.id);
    location.assign(entity);
    return location;
});

But I prefer you choose, because you know the code better and I don't finish to understand when to use EntityRepository.create() or new Entity() and Entity.assign() (Surely I will ask you at stackoverflow about this).

@B4nan
Copy link
Member

B4nan commented Apr 9, 2019

Fluent interface to entity.assign() also came to my mind. I will probably do all 3 things, fluent interface for entity.assign(), boolean toggle for EM.create() to allow extra properties, and @Propery({ persist: false: }) so one can whitelist only specific properties that are allowed.

I expect to have some time for this later this week, will ping you here once its published. Or feel free to send PR, 1. and 2. are really small changes. 3. will be probably more challenging and will require some additional tests, I can handle that myself.

Btw there is also EM.merge(), that behaves similarly to EM.create() :] I will definitely write something about this into docs later, but you can check tests to see how those things differ in the meanwhile. Currently I am trying to gather some feedback on reddit and once I have enough, I will create FAQ page. I also published an article about MikroORM: https://medium.com/dailyjs/introducing-mikro-orm-typescript-data-mapper-orm-with-identity-map-9ba58d049e02

@B4nan
Copy link
Member

B4nan commented Apr 11, 2019

Shadow properties implemented in 6062118

I saw you were forking the repo, are you up to implement 1. and 2.? If not I will do that myself, but will be glad for another collaborator :)

@ghost
Copy link
Author

ghost commented Apr 11, 2019

No, I was trying the MongoDB transactions. I was too ambitious. I can't see how to handle the possible nested transactions.

@B4nan
Copy link
Member

B4nan commented Apr 14, 2019

Released v2.2 that includes shadow properties.

@ghost
Copy link
Author

ghost commented Apr 15, 2019

Great, I expect to have some time to try it later this week.

Thanks.

pepakriz pushed a commit to pepakriz/mikro-orm that referenced this issue Oct 5, 2019
This allows to mark properties that will not be persisted into database, but can be assigned via entity manager methods like `create()` or `merge()`.

Closes mikro-orm#40
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant