Skip to content

Commit

Permalink
Improvement: added preserve null option documentation.
Browse files Browse the repository at this point in the history
  • Loading branch information
dpimonov committed Jul 20, 2022
1 parent d4e3db3 commit 487f650
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 35 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Preserve null option.
- Performance improvements.

### Changed

- Simplify handling of object references inside serializers.
- Separate modules are now merged into one to reduce final application bundle size and simplify usage.

### Removed
Expand Down
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ If you like or are using this project please give it a star. Thanks!
* [Injector option](#injector-option)
* [Naming convention option](#naming-convention-option)
* [Preserve discriminator option](#preserve-discriminator-option)
* [Preserve null option](#preserve-null-option)
* [Reference handler option](#reference-handler-option)
* [Serializable option](#serializable-option)
* [Serializer option](#serializer-option)
Expand Down Expand Up @@ -699,7 +700,7 @@ import { Type, Property } from '@dipscope/type-manager';
})
export class User
{
@Property(String, { serializedDefaultValue: 'BestName', deserializedDefaultValue: 'BestName' }) public name: string;
@Property(String, { serializedDefaultValue: 'SerializedName', deserializedDefaultValue: 'DeserializedName' }) public name: string;
}
```

Expand Down Expand Up @@ -866,6 +867,24 @@ export class User

By default discriminator is not preserved and only used during deserialization of polymorphic types. You can read more about handling of polymorphic types in this [section](#configuring-usage-of-polymorphic-types).

### Preserve null option

This option defines if null values should be preserved during serialization and deserialization.

```typescript
import { Type, Property } from '@dipscope/type-manager';

@Type({
preserveNull: true
})
export class User
{
@Property(String, { preserveNull: false }) public name: string;
}
```

By default null values are preserved. You can set it to `false` per type, property or globally using `TypeManager` configure method. This will result in treating null values as undefined so you will get all related behaviours like setting default values.

### Reference handler option

This option can be used both on type and property to specify how references to the same objects should be handled during serialization and deserialization.
Expand Down
35 changes: 28 additions & 7 deletions src/serializer-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -567,18 +567,39 @@ export class SerializerContext<TType> extends Metadata
return;
}

/**
* Defines serializer context options based on partial.
*
* @param {Partial<SerializerContextOptions<any>>} serializerContextOptions Partial serializer context options.
*
* @returns {SerializerContextOptions<any>} Complete serializer context options.
*/
private defineSerializerContextOptions(serializerContextOptions: Partial<SerializerContextOptions<any>>): SerializerContextOptions<any>
{
return {
jsonPathKey: serializerContextOptions.jsonPathKey ?? this.serializerContextOptions.jsonPathKey,
typeMetadata: serializerContextOptions.typeMetadata ?? this.serializerContextOptions.typeMetadata,
genericArguments: serializerContextOptions.genericArguments ?? this.serializerContextOptions.genericArguments,
propertyMetadata: serializerContextOptions.propertyMetadata ?? this.serializerContextOptions.propertyMetadata,
referenceValueSetter: serializerContextOptions.referenceValueSetter ?? this.serializerContextOptions.referenceValueSetter
};
}

/**
* Defines child serializer context.
*
* Called by serializers on drill down.
*
* @param {SerializerContextOptions<any>} serializerContextOptions Child serializer context options.
* @param {Partial<SerializerContextOptions<any>>} childSerializerContextOptions Child serializer context options.
*
* @returns {SerializerContext<any>} Child serializer context.
*/
public defineChildSerializerContext(serializerContextOptions: SerializerContextOptions<any>): SerializerContext<any>
public defineChildSerializerContext(childSerializerContextOptions: Partial<SerializerContextOptions<any>>): SerializerContext<any>
{
return new SerializerContext(this.$, this.referenceMap, this.referenceCallbackMap, serializerContextOptions, this);
const parentSerializerContext = isNil(childSerializerContextOptions.jsonPathKey) ? this.parentSerializerContext : this;
const serializerContextOptions = this.defineSerializerContextOptions(childSerializerContextOptions);

return new SerializerContext(this.$, this.referenceMap, this.referenceCallbackMap, serializerContextOptions, parentSerializerContext);
}

/**
Expand Down Expand Up @@ -609,7 +630,7 @@ export class SerializerContext<TType> extends Metadata
const genericTypeArgument = isArray(genericArgument) ? genericArgument[0] : genericArgument;
const genericGenericArguments = isArray(genericArgument) ? genericArgument[1] : undefined;
const typeMetadata = this.defineTypeMetadata(genericTypeArgument);
const serializerContextOptions = Object.assign({}, this.serializerContextOptions);
const serializerContextOptions = this.defineSerializerContextOptions(this.serializerContextOptions);

serializerContextOptions.typeMetadata = typeMetadata;
serializerContextOptions.genericArguments = genericGenericArguments;
Expand Down Expand Up @@ -649,7 +670,7 @@ export class SerializerContext<TType> extends Metadata
}

const typeMetadata = this.defineTypeMetadata(typeFn);
const serializerContextOptions = Object.assign({}, this.serializerContextOptions);
const serializerContextOptions = this.defineSerializerContextOptions(this.serializerContextOptions);

serializerContextOptions.typeMetadata = typeMetadata;

Expand All @@ -671,14 +692,14 @@ export class SerializerContext<TType> extends Metadata

if (record[typeMetadata.discriminator] === discriminant)
{
const serializerContextOptions = Object.assign({}, this.serializerContextOptions);
const serializerContextOptions = this.defineSerializerContextOptions(this.serializerContextOptions);

serializerContextOptions.typeMetadata = typeMetadata;

return new SerializerContext(this.$, this.referenceMap, this.referenceCallbackMap, serializerContextOptions, this.parentSerializerContext);
}
}

throw new Error(`${this.jsonPath}: cannot define discriminant of polymorphic type. This is usually caused by invalid configuration.`);
}
}
2 changes: 0 additions & 2 deletions src/serializers/array-serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ export class ArraySerializer implements Serializer<Array<any>>
{
const valueSerializerContext = genericSerializerContext.defineChildSerializerContext({
jsonPathKey: i,
typeMetadata: genericSerializerContext.typeMetadata,
referenceValueSetter: v => arrayOutput[i] = v
});

Expand Down Expand Up @@ -95,7 +94,6 @@ export class ArraySerializer implements Serializer<Array<any>>
{
const valueSerializerContext = genericSerializerContext.defineChildSerializerContext({
jsonPathKey: i,
typeMetadata: genericSerializerContext.typeMetadata,
referenceValueSetter: v => arrayOutput[i] = v
});

Expand Down
26 changes: 4 additions & 22 deletions src/serializers/map-serializer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { PropertyName } from 'lodash';
import isArray from 'lodash/isArray';
import isFunction from 'lodash/isFunction';
import isMap from 'lodash/isMap';
import isNull from 'lodash/isNull';
import isUndefined from 'lodash/isUndefined';
Expand Down Expand Up @@ -67,24 +65,16 @@ export class MapSerializer implements Serializer<Map<any, any>>
array[i] = {};

const keySerializerContext = genericKeySerializerContext.defineChildSerializerContext({
jsonPathKey: i,
typeMetadata: genericKeySerializerContext.typeMetadata,
genericArguments: genericKeySerializerContext.genericArguments
jsonPathKey: i
}).defineChildSerializerContext({
jsonPathKey: MapSerializer.key,
typeMetadata: genericKeySerializerContext.typeMetadata,
genericArguments: genericKeySerializerContext.genericArguments,
referenceValueSetter: v => array[i][MapSerializer.key] = v
});

const valueSerializerContext = genericValueSerializerContext.defineChildSerializerContext({
jsonPathKey: i,
typeMetadata: genericValueSerializerContext.typeMetadata,
genericArguments: genericValueSerializerContext.genericArguments
jsonPathKey: i
}).defineChildSerializerContext({
jsonPathKey: MapSerializer.value,
typeMetadata: genericValueSerializerContext.typeMetadata,
genericArguments: genericValueSerializerContext.genericArguments,
referenceValueSetter: v => array[i][MapSerializer.value] = v
});

Expand Down Expand Up @@ -139,26 +129,18 @@ export class MapSerializer implements Serializer<Map<any, any>>
const v = array[i][MapSerializer.value];

const keySerializerContext = genericKeySerializerContext.defineChildSerializerContext({
jsonPathKey: i,
typeMetadata: genericKeySerializerContext.typeMetadata,
genericArguments: genericKeySerializerContext.genericArguments
jsonPathKey: i
}).defineChildSerializerContext({
jsonPathKey: MapSerializer.key,
typeMetadata: genericKeySerializerContext.typeMetadata,
genericArguments: genericKeySerializerContext.genericArguments,
referenceValueSetter: v => map.set(v, undefined)
});

const key = keySerializerContext.deserialize(k);

const valueSerializerContext = genericValueSerializerContext.defineChildSerializerContext({
jsonPathKey: i,
typeMetadata: genericValueSerializerContext.typeMetadata,
genericArguments: genericValueSerializerContext.genericArguments
jsonPathKey: i
}).defineChildSerializerContext({
jsonPathKey: MapSerializer.value,
typeMetadata: genericValueSerializerContext.typeMetadata,
genericArguments: genericValueSerializerContext.genericArguments,
referenceValueSetter: v => map.set(key, v)
});

Expand Down
3 changes: 0 additions & 3 deletions src/serializers/set-serializer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import isArray from 'lodash/isArray';
import isFunction from 'lodash/isFunction';
import isNull from 'lodash/isNull';
import isSet from 'lodash/isSet';
import isUndefined from 'lodash/isUndefined';
Expand Down Expand Up @@ -50,7 +49,6 @@ export class SetSerializer implements Serializer<Set<any>>

const valueSerializerContext = genericSerializerContext.defineChildSerializerContext({
jsonPathKey: i,
typeMetadata: genericSerializerContext.typeMetadata,
referenceValueSetter: v => array[i] = v
});

Expand Down Expand Up @@ -101,7 +99,6 @@ export class SetSerializer implements Serializer<Set<any>>
{
const valueSerializerContext = genericSerializerContext.defineChildSerializerContext({
jsonPathKey: i,
typeMetadata: genericSerializerContext.typeMetadata,
referenceValueSetter: v => set.add(v)
});

Expand Down

0 comments on commit 487f650

Please sign in to comment.