Skip to content
This repository has been archived by the owner on Jun 10, 2020. It is now read-only.

Commit

Permalink
Merge pull request #2 from typed-project/converter
Browse files Browse the repository at this point in the history
Converter
  • Loading branch information
vincent178 committed Apr 16, 2017
2 parents 0568dd7 + 90f6de9 commit 588b2b0
Show file tree
Hide file tree
Showing 20 changed files with 768 additions and 59 deletions.
18 changes: 9 additions & 9 deletions src/caster/Caster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,26 @@ export class Caster {
switch (returnType.name) {

case "String":
return value.toString();

return "" + value;

case "Boolean":
if (value === 'true') {
return true;
} else if (value === 'false') {
return false;
} else {
throw new Error(`[TYPED] cast ${value} to boolean error`);
}

if (value === 'true') return true;
if (value === 'false') return false;

return !!value;

case "Number":
return parseInt(value, 10);
return +value;

case "Object":
return value;

}

} else {

throw new Error(`[TYPED] not support cast to type: ${returnType.name}`);
}

Expand Down
7 changes: 7 additions & 0 deletions src/converter/ConvertServiceOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

export interface ConvertServiceOptions {

returnType?: Function;

customConverter?: Function|Function[];
}
6 changes: 6 additions & 0 deletions src/converter/ConverterMetadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

export class ConverterMetadata {

private _type: Function;

}
10 changes: 10 additions & 0 deletions src/converter/ConverterRegistry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {IConverter} from "./interface/IConverter";

export class ConverterRegistry {

private static _converters: Map<Function, IConverter> = new Map();

public static registerConverter(type: Function, converter: IConverter) {
this._converters.set(type, converter);
}
}
118 changes: 118 additions & 0 deletions src/converter/ConverterService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import {Service} from "../mvc/decorator/Service";
import {PropertyRegistry} from "./PropertyRegistry";
import {PropertyMetadata} from "./PropertyMetadata";
import * as _ from "lodash";
import {TypeUtil} from "../util/TypeUtil";
import {Klass} from "../core/Klass";

/**
* ConverterService used to convert class to object and vice-versa.
*/
@Service()
export class ConverterService {

public convert(data: any, returnType: Function, baseType?: Function) {

const type = data.constructor;
let properties;

if (returnType === type && typeof baseType === 'undefined') {
return data;
}

if (_.isUndefined(data) || _.isNull(data)) {
return data;
}

if (returnType === String) {
return "" + data;
}

if (returnType === Number) {
return +data;
}

if (returnType === Boolean) {
if (data === 'true') return true;
if (data === 'false') return false;

return !!data;
}

if (returnType === Date) {
return new Date(data);
}

if (returnType === Array && type === Array && baseType) {
return data.map(item => this.convert(item, baseType));
}

if (returnType === Map && type === Map && baseType) {
const result = new Map();

data.forEach((value, key) => {
result.set(key, this.convert(value, baseType));
});

return result;
}

/*
*
* Convert class instance to object
* If provide a converter, and implement serialize function
* it will use serialize function result as the property value
*
*/

properties = PropertyRegistry.properties.get(type);
if (returnType === Object && !TypeUtil.isSimpleType(type) && properties) {

const result = {};

properties.forEach((metadata: PropertyMetadata) => {
let value = data[metadata.klassProperty];

value = this.convert(value, metadata.propertyType, metadata.baseType);

if (metadata.converter && metadata.converter.serialize) {
value = metadata.converter.serialize(data, metadata.klassProperty, metadata.objectProperty);
}

result[metadata.objectProperty] = value;
});

return result;
}

/*
*
* Convert object to class instance
* If provide a converter, and implement deserialize function
* it will use deserialize function result as the property value
*
*/
properties = PropertyRegistry.properties.get(returnType);
if (type === Object && !TypeUtil.isSimpleType(returnType) && properties) {

const klass = <Klass> returnType;
const ins = new klass();

properties.forEach((metadata: PropertyMetadata) => {
let value = data[metadata.objectProperty];

value = this.convert(value, metadata.propertyType, metadata.baseType);

if (metadata.converter && metadata.converter.deserialize) {
value = metadata.converter.deserialize(data, metadata.klassProperty, metadata.objectProperty);
}

ins[metadata.klassProperty] = value;
});

return ins;
}

throw new Error(`not support convert data`);
}
}
55 changes: 55 additions & 0 deletions src/converter/PropertyMetadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import {IConverter} from "./interface/IConverter";

export class PropertyMetadata {

private _type: Function;

private _klassProperty: string;

private _objectProperty: string;

private _propertyType: Function;

private _converter: IConverter;

private _baseType: Function;

get type(): Function {
return this._type;
}

get objectProperty(): string {
return this._objectProperty;
}

get klassProperty(): string {
return this._klassProperty;
}

get propertyType(): Function {
return this._propertyType;
}

get converter(): IConverter {
return this._converter;
}

set converter(value: IConverter) {
this._converter = value;
}

get baseType(): Function {
return this._baseType;
}

set baseType(value: Function) {
this._baseType = value;
}

constructor(type: Function, klassProperty: string, objectProperty: string, propertyType: Function) {
this._type = type;
this._objectProperty = objectProperty;
this._klassProperty = klassProperty;
this._propertyType = propertyType;
}
}
10 changes: 10 additions & 0 deletions src/converter/PropertyOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {IConverter} from "./interface/IConverter";

export interface PropertyOptions {

name?: string;

converter?: IConverter;

baseType?: Function;
}
68 changes: 68 additions & 0 deletions src/converter/PropertyRegistry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {PropertyMetadata} from "./PropertyMetadata";
import {PropertyOptions} from "./PropertyOptions";
import {Reflection} from "../core/Reflection";
import * as _ from 'lodash';

export class PropertyRegistry {

public static properties: Map<Function, PropertyMetadata[]> = new Map();


public static registerObjectProperty(type: Function, klassProperty: string, nameOrOptions?: string|PropertyOptions) {
const properties = this.findProperties(type);

const propertyType = Reflection.getType(type.prototype, klassProperty);

let objectProperty = klassProperty;
let converter;
let baseType;

if (typeof nameOrOptions !== 'undefined') {

if (_.isString(nameOrOptions)) {

objectProperty = nameOrOptions;

} else {

const options = <PropertyOptions> nameOrOptions;

if (typeof options.name !== 'undefined') {
objectProperty = options.name;
}

if (typeof options.converter !== 'undefined') {
converter = options.converter;
}

if (typeof options.baseType !== 'undefined') {
baseType = options.baseType;
}

}
}

const propertyMetadata = new PropertyMetadata(type, klassProperty, objectProperty, propertyType);

if (converter) {
propertyMetadata.converter = converter;
}

if (baseType) {
propertyMetadata.baseType = baseType;
}

properties.push(propertyMetadata);
}

public static findProperties(type: Function) {
let properties = this.properties.get(type);

if (typeof properties === 'undefined') {
properties = [];
this.properties.set(type, properties);
}

return properties;
}
}
9 changes: 0 additions & 9 deletions src/converter/decorator/JsonProperty.ts

This file was deleted.

12 changes: 12 additions & 0 deletions src/converter/decorator/ObjectProperty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {PropertyRegistry} from "../PropertyRegistry";
import {PropertyOptions} from "../PropertyOptions";

export function ObjectProperty(nameOrOptions?: string|PropertyOptions) {

return (target: any, propertyName: string) => {

PropertyRegistry.registerObjectProperty(target.constructor, propertyName, nameOrOptions);

};

}
8 changes: 8 additions & 0 deletions src/converter/interface/IConverter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

export interface IConverter {

serialize?(data: any, klassProperty: string, objectProperty: string): any;

deserialize?(data: any, klassProperty: string, objectProperty: string): any;

}
2 changes: 1 addition & 1 deletion src/core/Reflection.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export class Reflection {

public static getType(type: Function, key?: string) {
public static getType(type: any, key?: string) {
return (<any> Reflect).getMetadata("design:type", type, key);
}

Expand Down
Loading

0 comments on commit 588b2b0

Please sign in to comment.