From 97b432cb77be305ef822161951d9f1f46fdfc1cc Mon Sep 17 00:00:00 2001 From: Theo Sun Date: Sun, 20 Jun 2021 12:13:17 +0800 Subject: [PATCH] fix: primitive value issue --- package-lock.json | 8 +-- package.json | 2 +- src/builder/filter.ts | 25 ++++---- src/builder/index.ts | 1 + src/builder/types.ts | 111 +++++++++++++++++++++--------------- test/builder/filter.test.ts | 24 +++++++- test/filter.spec.ts | 6 +- 7 files changed, 111 insertions(+), 66 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7f34392..baa9715 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1209,12 +1209,12 @@ } }, "@odata/metadata": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@odata/metadata/-/metadata-0.2.2.tgz", - "integrity": "sha512-iUKqnblmNwNtvmbaXRJtO6XELam/KAzEJEs3cohGWEKaiTeUhmrq+vjXjrzea3HQlelpVHPke/58q1IYHvbjUw==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@odata/metadata/-/metadata-0.2.4.tgz", + "integrity": "sha512-jab1OVxUELm89z6yq055O7NdVJukAgKyNUVONZii8TYuMgUiY8cUhs7Mi8VDJv7w3SiBHzIPGhuY0jQM0eHLQw==", "dev": true, "requires": { - "@newdash/newdash": "^5.15.0", + "@newdash/newdash": "^5.19.0", "reflect-metadata": "^0.1.13" } }, diff --git a/package.json b/package.json index 2450143..fe644ce 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "release": "standard-version --no-verify && git push --follow-tags origin master" }, "devDependencies": { - "@odata/metadata": "^0.2.2", + "@odata/metadata": "^0.2.4", "@types/jest": "^26.0.23", "@types/node": "^14.14.41", "@typescript-eslint/eslint-plugin": "^4.27.0", diff --git a/src/builder/filter.ts b/src/builder/filter.ts index 003e916..b80c36d 100644 --- a/src/builder/filter.ts +++ b/src/builder/filter.ts @@ -1,5 +1,6 @@ import join from '@newdash/newdash/join'; -import { ODataDataObject } from './types'; +import { Edm } from '@odata/metadata'; +import { convertPrimitiveValueToString } from './types'; export enum ExprOperator { eq = 'eq', @@ -47,6 +48,10 @@ class ODataFieldExpr { private _addExpr(op: ExprOperator, value: any) { + if (value === null) { + this._getFieldExprs().push({ op, value: 'null' }) + } + switch (typeof value) { case 'number': case 'boolean': this._getFieldExprs().push({ op, value: `${value}` }); @@ -59,8 +64,8 @@ class ODataFieldExpr { } break; case 'object': - if (value instanceof ODataDataObject) { - this._getFieldExprs().push({ op, value: value.toString() }); + if (value instanceof Edm.PrimitiveTypeValue) { + this._getFieldExprs().push({ op, value: convertPrimitiveValueToString(value) }); } else { throw new Error(`Not support object ${value?.constructor?.name || typeof value} in odata filter eq/ne/gt/ge/ne/nt ...`); } @@ -77,7 +82,7 @@ class ODataFieldExpr { * equal * @param value */ - eq(value: number | string | ODataDataObject): ODataFilter { + eq(value: number | string | Edm.PrimitiveTypeValue): ODataFilter { this._addExpr(ExprOperator.eq, value); return this._filter; } @@ -86,7 +91,7 @@ class ODataFieldExpr { * not equal * @param value */ - ne(value: number | string | ODataDataObject): ODataFilter { + ne(value: number | string | Edm.PrimitiveTypeValue): ODataFilter { this._addExpr(ExprOperator.ne, value); return this._filter; } @@ -105,7 +110,7 @@ class ODataFieldExpr { * greater or equal * @param value */ - ge(value: number | string | ODataDataObject): ODataFilter { + ge(value: number | string | Edm.PrimitiveTypeValue): ODataFilter { this._addExpr(ExprOperator.ge, value); return this._filter; } @@ -114,7 +119,7 @@ class ODataFieldExpr { * greater than * @param value */ - gt(value: number | string | ODataDataObject): ODataFilter { + gt(value: number | string | Edm.PrimitiveTypeValue): ODataFilter { this._addExpr(ExprOperator.gt, value); return this._filter; } @@ -123,7 +128,7 @@ class ODataFieldExpr { * less or equal * @param value */ - le(value: number | string | ODataDataObject): ODataFilter { + le(value: number | string | Edm.PrimitiveTypeValue): ODataFilter { this._addExpr(ExprOperator.le, value); return this._filter; } @@ -132,7 +137,7 @@ class ODataFieldExpr { * less than * @param value */ - lt(value: number | string | ODataDataObject): ODataFilter { + lt(value: number | string | Edm.PrimitiveTypeValue): ODataFilter { this._addExpr(ExprOperator.lt, value); return this._filter; } @@ -142,7 +147,7 @@ class ODataFieldExpr { * * @param values */ - in(values: Array = []): ODataFilter { + in(values: Array = []): ODataFilter { if (values.length > 0) { values.forEach((value) => { this.eq(value); diff --git a/src/builder/index.ts b/src/builder/index.ts index d7bf4b7..f7547b1 100644 --- a/src/builder/index.ts +++ b/src/builder/index.ts @@ -1,6 +1,7 @@ import { ODataFilter } from './filter'; import { ODataParam } from './param'; +export { Edm } from "@odata/metadata"; export * from './batch'; export * from './filter'; export * from './param'; diff --git a/src/builder/types.ts b/src/builder/types.ts index ce17e3f..7983e26 100644 --- a/src/builder/types.ts +++ b/src/builder/types.ts @@ -1,57 +1,76 @@ +import { Edm } from "@odata/metadata"; -export abstract class ODataDataObject { - abstract toString(): string; -} - -export class ODataDateTimeV4 extends ODataDataObject { - - private constructor(date: Date) { - super(); - this._date = date; - } - - static from(date: Date): ODataDateTimeV4; - static from(date: string): ODataDateTimeV4; - static from(date: any): ODataDateTimeV4 { - switch (typeof date) { - case 'string': - return new ODataDateTimeV4(new Date(date)); - default: - return new ODataDateTimeV4(date); - } - } - - private _date: Date - - public toString(): string { - return `${this._date.toISOString()}`; +/** + * + * @param value primitive literal value + * @returns the string representation + */ +export function convertPrimitiveValueToString(value: Edm.PrimitiveTypeValue) { + if (value?.getValue?.() === null) { + return 'null' } -} - -export class ODataDateTimeOffsetV4 extends ODataDataObject { + if (value?.getValue?.() !== undefined) { - private constructor(date: Date) { - super(); - this._date = date; - } - - static from(date: Date): ODataDateTimeOffsetV4; - static from(date: string): ODataDateTimeOffsetV4; - static from(date: any): ODataDateTimeOffsetV4 { - switch (typeof date) { - case 'string': - return new ODataDateTimeOffsetV4(new Date(date)); + switch (value?.getType?.()) { + case Edm.Int16: + case Edm.Int32: + case Edm.Int64: + case Edm.Guid: + case Edm.Double: + case Edm.Decimal: + case Edm.Byte: + case Edm.SByte: + case Edm.Single: + return String(value.getValue()) + case Edm.Boolean: + return String(value.getValue()) + case Edm.Binary: + let vB = value.getValue() + if (vB instanceof Buffer) { + return `binary'${vB.toString("base64")}'` + } + return String(vB) + case Edm.String: + return `'${value.getValue()}'` + case Edm.Duration: + // TODO integrate with some other duration lib + return value.getValue(); + case Edm.DateTimeOffset: + let v1 = value.getValue() + if (typeof v1 === 'string') { + v1 = new Date(v1) + } + return v1.toISOString() + case Edm.Date: + const v2 = value.getValue() + if (v2 instanceof Date) { + return `${v2.getFullYear()}-${v2.getMonth() + 1}-${v2.getDate()}` + } + return v2 + case Edm.Geography: + case Edm.GeographyPoint: + case Edm.GeographyLineString: + case Edm.GeographyPolygon: + case Edm.GeographyMultiPoint: + case Edm.GeographyMultiLineString: + case Edm.GeographyMultiPolygon: + case Edm.GeographyCollection: + case Edm.Geometry: + case Edm.GeometryPoint: + case Edm.GeometryLineString: + case Edm.GeometryPolygon: + case Edm.GeometryMultiPoint: + case Edm.GeometryMultiLineString: + case Edm.GeometryMultiPolygon: + case Edm.GeometryCollection: + return String(value.getValue()) default: - return new ODataDateTimeOffsetV4(date); + throw new TypeError(`not support type '${value.getType()}'`) } } + throw new Error("'undefined' value provided") - private _date: Date - - public toString(): string { - return `${this._date.toISOString()}`; - } } diff --git a/test/builder/filter.test.ts b/test/builder/filter.test.ts index ed43970..2ce3940 100644 --- a/test/builder/filter.test.ts +++ b/test/builder/filter.test.ts @@ -1,10 +1,11 @@ -import { filter, ODataFilter } from '../../src'; +import { Edm, filter, ODataFilter } from '../../src'; describe('OData Query Builder - Filter Test Suite', () => { it('should support filter by value/name', () => { expect(ODataFilter.New().field('A').eq('a').toString()).toBe("A eq 'a'"); + expect(ODataFilter.New().field('A').eq(Edm.String.createValue("a")).toString()).toBe("A eq 'a'"); expect(ODataFilter.New().field('A').eq(1).toString()).toBe('A eq 1'); }); @@ -15,10 +16,29 @@ describe('OData Query Builder - Filter Test Suite', () => { B: string; } expect(ODataFilter.New({ A: 1, B: '2' }).toString()).toBe("A eq 1 and B eq '2'"); + + expect(ODataFilter.New({ + A: Edm.Int16.createValue(12), + B: Edm.String.createValue('12') + }).toString()).toBe("A eq 12 and B eq '12'"); }); it('should support filter alias', () => { - expect(filter({A:1}).build()).toBe('A eq 1'); + expect(filter({ A: 1 }).build()).toBe('A eq 1'); + }); + + it('should support filter guid', () => { + expect( + filter() + .field("A") + .eq(Edm.Guid.createValue("253f842d-d739-41b8-ac8c-139ac7a9dd14")) + .build() + ).toBe("A eq 253f842d-d739-41b8-ac8c-139ac7a9dd14") + + expect( + filter({ A: Edm.Guid.createValue("253f842d-d739-41b8-ac8c-139ac7a9dd14") }) + .build() + ).toBe("A eq 253f842d-d739-41b8-ac8c-139ac7a9dd14") }); }); diff --git a/test/filter.spec.ts b/test/filter.spec.ts index 13db149..edccb5c 100644 --- a/test/filter.spec.ts +++ b/test/filter.spec.ts @@ -1,6 +1,6 @@ import { get } from '@newdash/newdash'; import { Edm } from "@odata/metadata"; -import { defaultParser, ODataDateTimeOffsetV4, ODataDateTimeV4, ODataFilter } from '../src'; +import { defaultParser, ODataFilter } from '../src'; describe('Filter Test Suite', () => { @@ -29,8 +29,8 @@ describe('Filter Test Suite', () => { .field('F').between(1, 3, true) .field('E').in(['a', 'c', 'd']) .field('year(Date)').eq(2010) - .field('Date2').gt(ODataDateTimeOffsetV4.from('2020-07-30T03:16:27.023Z')) - .field('Date3').lt(ODataDateTimeV4.from(new Date())) + .field('Date2').gt(Edm.DateTimeOffset.createValue('2020-07-30T03:16:27.023Z')) + .field('Date3').lt(Edm.DateTimeOffset.createValue(new Date())) .toString(); defaultParser.filter(sFilter);