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

Add partial fetching of nested embeddable #4199

Closed
acrosett opened this issue Apr 7, 2023 · 4 comments
Closed

Add partial fetching of nested embeddable #4199

acrosett opened this issue Apr 7, 2023 · 4 comments
Labels
enhancement New feature or request
Milestone

Comments

@acrosett
Copy link
Contributor

acrosett commented Apr 7, 2023

Given the following entity with an object embeddable :

@Entity()
export class User {

  @PrimaryKey({serializedName: '_id' })
  _id: ObjectId;
  
  @Property()
  email: string;

  @Embedded(() => ProfileSchema, { nullable: true, object: true })
  profile: ProfileSchema;

}

@Embeddable()
export class ProfileSchema {

  @Property({ nullable: true })
  first: string;

  @Property()
  @Index()
  last: string;

  @Property()
  age: number;

}

I would like the following request :

await em.find(User, { email : 'exemple@mail.com' }, { fields: ['email', 'profile.first', 'profile.age']})

to return the following partial entity :

{
  email: 'exemple@mail.com',
  profile: { first: 'John', age: 30 },
}
@acrosett acrosett added the enhancement New feature or request label Apr 7, 2023
@acrosett acrosett changed the title Add partial fetching of embeddable Add partial fetching of nested embeddable Apr 7, 2023
@B4nan
Copy link
Member

B4nan commented Apr 7, 2023

How do you expect that to work with object embeddable? It is all a single field, you cant load it partially.

@acrosett
Copy link
Contributor Author

acrosett commented Apr 7, 2023

I would expect it to work like the project fields feature of MongoDB, by applying a filter after the initial load.

I'm currently doing it with a custom function (testing in progress) :

    /**
   * Returns a new object that contains only the fields of the input object that match the list of fields.
   * Handles nested fields and returns partial nested fields if present.
   * @param {Object} obj - The input object to filter.
   * @param {Array} fields - An array of strings representing the fields to include in the output object.
   * @returns {Object} - A new object with only the specified fields.
   */
  selectFieldsFromObject(obj: any, fields: string[]): any {
    const result = {};
    for (const key of fields) {
      if (obj?.hasOwnProperty(key)) {
        result[key] = obj[key];
      } else if (key.includes('.')) {
        const [outerKey, ...innerKeys] = key.split('.');
        const innerKey = innerKeys.join('.');
        if (obj?.hasOwnProperty(outerKey)) {
          if (Array.isArray(obj[outerKey])) {
            const filtered = obj[outerKey].map((item) => {
              return this.selectFieldsFromObject(item, [innerKey]);
            });
            if (filtered.length > 0) {
              result[outerKey] = result[outerKey] || [];
              result[outerKey] = [...result[outerKey], ...filtered];
            }
          } else {
            const filtered = this.selectFieldsFromObject(obj[outerKey], [innerKey]);
            if (Object.keys(filtered).length > 0) {
              result[outerKey] = { ...result[outerKey], ...filtered };
            }
          }
        }
      }
    }
    return result;
  }

However it would be nice to have this feature integrated into the orm.

@B4nan
Copy link
Member

B4nan commented Apr 7, 2023

Ok that could work for sure.

@B4nan B4nan added this to the 6.0 milestone Apr 7, 2023
B4nan added a commit that referenced this issue Apr 11, 2023
#4203)

## Implicit serialization changes

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

## `serialize` helper always returns array

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes #4138 
Closes #4199
@B4nan
Copy link
Member

B4nan commented Apr 11, 2023

Closing via #4203

@B4nan B4nan closed this as completed Apr 11, 2023
B4nan added a commit that referenced this issue Apr 12, 2023
#4203)

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes #4138
Closes #4199
B4nan added a commit that referenced this issue Apr 26, 2023
#4203)

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes #4138
Closes #4199
jsprw pushed a commit to jsprw/mikro-orm-full-text-operators that referenced this issue May 7, 2023
mikro-orm#4203)

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes mikro-orm#4138
Closes mikro-orm#4199
B4nan added a commit that referenced this issue May 14, 2023
#4203)

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes #4138
Closes #4199
B4nan added a commit that referenced this issue May 14, 2023
#4203)

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes #4138
Closes #4199
B4nan added a commit that referenced this issue May 24, 2023
#4203)

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes #4138
Closes #4199
B4nan added a commit that referenced this issue May 26, 2023
#4203)

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes #4138
Closes #4199
B4nan added a commit that referenced this issue Jun 11, 2023
#4203)

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes #4138
Closes #4199
B4nan added a commit that referenced this issue Sep 10, 2023
#4203)

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes #4138
Closes #4199
B4nan added a commit that referenced this issue Sep 20, 2023
#4203)

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes #4138
Closes #4199
B4nan added a commit that referenced this issue Sep 24, 2023
#4203)

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes #4138
Closes #4199
B4nan added a commit that referenced this issue Sep 30, 2023
#4203)

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes #4138
Closes #4199
B4nan added a commit that referenced this issue Oct 2, 2023
#4203)

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes #4138
Closes #4199
B4nan added a commit that referenced this issue Oct 17, 2023
#4203)

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes #4138
Closes #4199
B4nan added a commit that referenced this issue Oct 21, 2023
#4203)

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes #4138
Closes #4199
B4nan added a commit that referenced this issue Oct 25, 2023
#4203)

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes #4138
Closes #4199
B4nan added a commit that referenced this issue Nov 2, 2023
#4203)

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes #4138
Closes #4199
B4nan added a commit that referenced this issue Nov 5, 2023
#4203)

Implicit serialization, so calling `toObject()` or `toJSON()` on the
entity, as opposed to explicitly using the `serialize()` helper, now
works entirely based on `populate` hints. This means that, unless you
explicitly marked some entity as populated via
`wrap(entity).populated()`, it will be part of the serialized form only
if it was part of the `populate` hint:

```ts
// let's say both Author and Book entity has a m:1 relation to Publisher entity
// we only populate the publisher relation of the Book entity
const user = await em.findOneOrFail(Author, 1, {
  populate: ['books.publisher'],
});

const dto = wrap(user).toObject();
console.log(dto.publisher); // only the FK, e.g. `123`
console.log(dto.books[0].publisher); // populated, e.g. `{ id: 123, name: '...' }`
```

Moreover, the implicit serialization now respects the partial loading
hints too. Previously, all loaded properties were serialized, partial
loading worked only on the database query level. Since v6, we also prune
the data on runtime. This means that unless the property is part of the
partial loading hint (`fields` option), it won't be part of the DTO -
only exception is the primary key, you can optionally hide it via
`hidden: true` in the property options. Main difference here will be the
foreign keys, those are often automatically selected as they are needed
to build the entity graph, but will no longer be part of the DTO.

```ts
const user = await em.findOneOrFail(Author, 1, {
  fields: ['books.publisher.name'],
});

const dto = wrap(user).toObject();
// only the publisher's name will be available, previously there would be also `book.author`
// `{ id: 1, books: [{ id: 2, publisher: { id: 3, name: '...' } }] }`
```

**This also works for embeddables, including nesting and object mode.**

This method used to return a single object conditionally based on its
inputs, but the solution broke intellisense for the `populate` option.
The method signature still accepts single object or an array of objects,
but always returns an array.

To serialize single entity, you can use array destructing, or use
`wrap(entity).serialize()` which handles a single entity only.

```ts
const dtos = serialize([user1, user, ...], { exclude: ['id', 'email'], forceObject: true });
const [dto1] = serialize(user, { exclude: ['id', 'email'], forceObject: true });
const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
```

Closes #4138
Closes #4199
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

2 participants