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

API DTO Implementation #32

Merged
merged 5 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,13 @@ console.info(angle.toString(AngleUnits.Radians)); // 3.141592653589793 rad

// Specify fraction digits max length
console.info(angle.toString(AngleUnits.Radians, 2)); // 3.14 rad
```

## Additional methods

// Additional methods
Check, compare, calculate etc. with unitsnet:

```typescript
const length1 = Length.FromMeters(10);
const length2 = Length.FromDecimeters(100);
const length3 = Length.FromMeters(3);
Expand Down Expand Up @@ -107,9 +111,39 @@ setArithmeticFormula(ArithmeticOperation.Add, (valueA: number, valueB: number) =

// The numeral formula results
console.log(lengthA.add(lengthB).Meters); // 0.3
```

## DTO - Data Transfer Object

As UnitsNet provides a convenient way to work within a running service, there are occasions where the data needs to be exposed outside of the service, typically through an API containing the unit value or consumed from an API.

To support this with a clear API schema and make it easy to convert to and from this schema to the specific format, it's recommended to use DTOs and the UnitsNet flavor converters.

```typescript
import { Length, LengthDto, LengthUnits } from 'unitsnet-js';

// Create a Length unit object
const length = Length.FromMeters(100.01);

// Obtain the DTO object, represented by the default unit - meter
const lengthDto: LengthDto = length.toDto(); // {"value":100.01,"unit":"Meter"}

// Obtain the same value but represent DTO in KM
const lengthDtoRepresentsInKM: LengthDto = length.toDto(LengthUnits.Kilometers); // {"value":0.10001,"unit":"Kilometer"}

// Obtain Length object from lengthDto

const lengthFromMetersDto = Length.FromDto(lengthDto);
// The exact same value as
const lengthFromKMDto = Length.FromDto(lengthDtoRepresentsInKM);
```


Check out the OpenAPI [unitsnet-openapi-spec](https://haimkastner.github.io/unitsnet-openapi-spec-example/) example schema.

Also, refer to the detailed discussions on GitHub: [haimkastner/unitsnet-js#31](https://github.com/haimkastner/unitsnet-js/issues/31) & [angularsen/UnitsNet#1378](https://github.com/angularsen/UnitsNet/issues/1378).


### Supported units

The package provides support for the following units:
Expand Down
36 changes: 35 additions & 1 deletion generator-scripts/src/assets/README.t.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,13 @@ console.info(angle.toString(AngleUnits.Radians)); // 3.141592653589793 rad

// Specify fraction digits max length
console.info(angle.toString(AngleUnits.Radians, 2)); // 3.14 rad
```

## Additional methods

// Additional methods
Check, compare, calculate etc. with unitsnet:

```typescript
const length1 = Length.FromMeters(10);
const length2 = Length.FromDecimeters(100);
const length3 = Length.FromMeters(3);
Expand Down Expand Up @@ -107,9 +111,39 @@ setArithmeticFormula(ArithmeticOperation.Add, (valueA: number, valueB: number) =

// The numeral formula results
console.log(lengthA.add(lengthB).Meters); // 0.3
```

## DTO - Data Transfer Object

As UnitsNet provides a convenient way to work within a running service, there are occasions where the data needs to be exposed outside of the service, typically through an API containing the unit value or consumed from an API.

To support this with a clear API schema and make it easy to convert to and from this schema to the specific format, it's recommended to use DTOs and the UnitsNet flavor converters.

```typescript
import { Length, LengthDto, LengthUnits } from 'unitsnet-js';

// Create a Length unit object
const length = Length.FromMeters(100.01);

// Obtain the DTO object, represented by the default unit - meter
const lengthDto: LengthDto = length.toDto(); // {"value":100.01,"unit":"Meter"}

// Obtain the same value but represent DTO in KM
const lengthDtoRepresentsInKM: LengthDto = length.toDto(LengthUnits.Kilometers); // {"value":0.10001,"unit":"Kilometer"}

// Obtain Length object from lengthDto

const lengthFromMetersDto = Length.FromDto(lengthDto);
// The exact same value as
const lengthFromKMDto = Length.FromDto(lengthDtoRepresentsInKM);
```


Check out the OpenAPI [unitsnet-openapi-spec](https://haimkastner.github.io/unitsnet-openapi-spec-example/) example schema.

Also, refer to the detailed discussions on GitHub: [haimkastner/unitsnet-js#31](https://github.com/haimkastner/unitsnet-js/issues/31) & [angularsen/UnitsNet#1378](https://github.com/angularsen/UnitsNet/issues/1378).


### Supported units

The package provides support for the following units:
Expand Down
100 changes: 98 additions & 2 deletions generator-scripts/src/unit-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
MethodDeclarationStructure,
EnumMemberStructure,
JSDocStructure,
ImportDeclarationStructure
ImportDeclarationStructure,
InterfaceDeclarationStructure
} from "ts-morph";
import { UnitProperties, UnitGenerateOptions } from "./models/units-properties";
import { pascalToCamelCase } from "./utiles";
Expand Down Expand Up @@ -46,6 +47,30 @@ function buildEnum(enumName: string, units: UnitProperties[]): EnumDeclarationSt
}
}

/**
* Build the unit DTO.
*/
function buildDto(Unit: UnitGenerateOptions, enumName: string): InterfaceDeclarationStructure {
return {
kind: StructureKind.Interface,
name: `${Unit.unitName}Dto`,
properties: [
{
name: 'value',
type: 'number',
docs: [`The value of the ${Unit.unitName}`]
},
{
name: 'unit',
type: enumName,
docs: [` The specific unit that the ${Unit.unitName} value is representing`]
}
],
isExported: true,
docs: [`API DTO represents a ${Unit.unitName}`]
}
}

/**
* Build the unit properties get accessors.
* For example for 'Angle' unit generate a get 'Degrees' get 'Radiand' etc.
Expand Down Expand Up @@ -204,6 +229,67 @@ return NaN;`
};
}

function buildConvertToDto(unitName: string, enumName: string, baseUnit: UnitProperties): MethodDeclarationStructure {
const docs: JSDocStructure = {
kind: StructureKind.JSDoc,
description: `Create API DTO represent a ${unitName} unit.`,
tags: [{
kind: StructureKind.JSDocTag,
tagName: 'param',
text: `holdInUnit The specific ${unitName} unit to be used in the unit representation at the DTO`
}]
};

return {
kind: StructureKind.Method,
name: 'toDto',
scope: Scope.Public,
parameters: [
{
name: 'holdInUnit',
type: enumName,
initializer: `${enumName}.${baseUnit.pluralName}`
}
],
docs: [docs],
returnType: `${unitName}Dto`,
statements:
`return {
value: this.convert(holdInUnit),
unit: holdInUnit
};`
};
}

function buildConvertFromDto(unitName: string): MethodDeclarationStructure {
const docs: JSDocStructure = {
kind: StructureKind.JSDoc,
description: `Create a ${unitName} unit from an API DTO representation.`,
tags: [{
kind: StructureKind.JSDocTag,
tagName: 'param',
text: `dto${unitName} The ${unitName} API DTO representation`
}]
};

return {
kind: StructureKind.Method,
name: 'FromDto',
scope: Scope.Public,
isStatic: true,
parameters: [
{
name: `dto${unitName}`,
type: `${unitName}Dto`
}
],
docs: [docs],
returnType: unitName,
statements:
`return new ${unitName}(dto${unitName}.value, dto${unitName}.unit);`
};
}

/**
* Build from base to unit convert method.
* @param enumName The unit enum name.
Expand Down Expand Up @@ -586,6 +672,9 @@ export function generateUnitClass(project: Project,
// Build the enum structure
const unitsEnum = buildEnum(enumName, units);

// Build the DTO interface
const dtoInterface = buildDto(unitProperties, enumName);

// Build the base value variable
const valueMember: PropertyDeclarationStructure = {
kind: StructureKind.Property,
Expand Down Expand Up @@ -613,6 +702,11 @@ export function generateUnitClass(project: Project,
// Build the constructor
const unitCtor = buildUnitCtor(unitName, enumName, baseUnit.pluralName);

// The DTO converters
const convertToDtoMethod = buildConvertToDto(unitName, enumName, baseUnit)
const convertFromDtoMethod = buildConvertFromDto(unitName)


// Build the static creator methods
const unitCreators = buildUnitCreatorsMethods(unitName, enumName, units);

Expand Down Expand Up @@ -650,6 +744,8 @@ export function generateUnitClass(project: Project,
ctors: [unitCtor],
methods: [
...unitCreators,
convertToDtoMethod,
convertFromDtoMethod,
convertToUnitMethod,
convertFromBaseMethod,
convertToBaseMethod,
Expand All @@ -671,7 +767,7 @@ export function generateUnitClass(project: Project,

// Build the unit file with the unit enum and class
const sourceFile = project.createSourceFile(`${unitsDestinationDirectory}/gen-units/${unitProperties.unitName.toLowerCase()}.g.ts`, {
statements: [importDeclaration, unitsEnum, unitClass]
statements: [importDeclaration, dtoInterface, unitsEnum, unitClass]
}, {
overwrite: true
});
Expand Down
27 changes: 27 additions & 0 deletions src/gen-units/absorbeddoseofionizingradiation.g.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { BaseUnit } from "../base-unit";

/** API DTO represents a AbsorbedDoseOfIonizingRadiation */
export interface AbsorbedDoseOfIonizingRadiationDto {
/** The value of the AbsorbedDoseOfIonizingRadiation */
value: number;
/** The specific unit that the AbsorbedDoseOfIonizingRadiation value is representing */
unit: AbsorbedDoseOfIonizingRadiationUnits;
}

/** AbsorbedDoseOfIonizingRadiationUnits enumeration */
export enum AbsorbedDoseOfIonizingRadiationUnits {
/** The gray is the unit of ionizing radiation dose in the SI, defined as the absorption of one joule of radiation energy per kilogram of matter. */
Expand Down Expand Up @@ -365,6 +373,25 @@ export class AbsorbedDoseOfIonizingRadiation extends BaseUnit {
return new AbsorbedDoseOfIonizingRadiation(value, AbsorbedDoseOfIonizingRadiationUnits.Megarads);
}

/**
* Create API DTO represent a AbsorbedDoseOfIonizingRadiation unit.
* @param holdInUnit The specific AbsorbedDoseOfIonizingRadiation unit to be used in the unit representation at the DTO
*/
public toDto(holdInUnit: AbsorbedDoseOfIonizingRadiationUnits = AbsorbedDoseOfIonizingRadiationUnits.Grays): AbsorbedDoseOfIonizingRadiationDto {
return {
value: this.convert(holdInUnit),
unit: holdInUnit
};
}

/**
* Create a AbsorbedDoseOfIonizingRadiation unit from an API DTO representation.
* @param dtoAbsorbedDoseOfIonizingRadiation The AbsorbedDoseOfIonizingRadiation API DTO representation
*/
public static FromDto(dtoAbsorbedDoseOfIonizingRadiation: AbsorbedDoseOfIonizingRadiationDto): AbsorbedDoseOfIonizingRadiation {
return new AbsorbedDoseOfIonizingRadiation(dtoAbsorbedDoseOfIonizingRadiation.value, dtoAbsorbedDoseOfIonizingRadiation.unit);
}

/**
* Convert AbsorbedDoseOfIonizingRadiation to a specific unit value.
* @param toUnit The specific unit to convert to
Expand Down
27 changes: 27 additions & 0 deletions src/gen-units/acceleration.g.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { BaseUnit } from "../base-unit";

/** API DTO represents a Acceleration */
export interface AccelerationDto {
/** The value of the Acceleration */
value: number;
/** The specific unit that the Acceleration value is representing */
unit: AccelerationUnits;
}

/** AccelerationUnits enumeration */
export enum AccelerationUnits {
/** */
Expand Down Expand Up @@ -323,6 +331,25 @@ export class Acceleration extends BaseUnit {
return new Acceleration(value, AccelerationUnits.MillistandardGravity);
}

/**
* Create API DTO represent a Acceleration unit.
* @param holdInUnit The specific Acceleration unit to be used in the unit representation at the DTO
*/
public toDto(holdInUnit: AccelerationUnits = AccelerationUnits.MetersPerSecondSquared): AccelerationDto {
return {
value: this.convert(holdInUnit),
unit: holdInUnit
};
}

/**
* Create a Acceleration unit from an API DTO representation.
* @param dtoAcceleration The Acceleration API DTO representation
*/
public static FromDto(dtoAcceleration: AccelerationDto): Acceleration {
return new Acceleration(dtoAcceleration.value, dtoAcceleration.unit);
}

/**
* Convert Acceleration to a specific unit value.
* @param toUnit The specific unit to convert to
Expand Down
27 changes: 27 additions & 0 deletions src/gen-units/amountofsubstance.g.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { BaseUnit } from "../base-unit";

/** API DTO represents a AmountOfSubstance */
export interface AmountOfSubstanceDto {
/** The value of the AmountOfSubstance */
value: number;
/** The specific unit that the AmountOfSubstance value is representing */
unit: AmountOfSubstanceUnits;
}

/** AmountOfSubstanceUnits enumeration */
export enum AmountOfSubstanceUnits {
/** */
Expand Down Expand Up @@ -386,6 +394,25 @@ export class AmountOfSubstance extends BaseUnit {
return new AmountOfSubstance(value, AmountOfSubstanceUnits.KilopoundMoles);
}

/**
* Create API DTO represent a AmountOfSubstance unit.
* @param holdInUnit The specific AmountOfSubstance unit to be used in the unit representation at the DTO
*/
public toDto(holdInUnit: AmountOfSubstanceUnits = AmountOfSubstanceUnits.Moles): AmountOfSubstanceDto {
return {
value: this.convert(holdInUnit),
unit: holdInUnit
};
}

/**
* Create a AmountOfSubstance unit from an API DTO representation.
* @param dtoAmountOfSubstance The AmountOfSubstance API DTO representation
*/
public static FromDto(dtoAmountOfSubstance: AmountOfSubstanceDto): AmountOfSubstance {
return new AmountOfSubstance(dtoAmountOfSubstance.value, dtoAmountOfSubstance.unit);
}

/**
* Convert AmountOfSubstance to a specific unit value.
* @param toUnit The specific unit to convert to
Expand Down
Loading