diff --git a/src/main/RdfMapper.ts b/src/main/RdfMapper.ts index 7bb24b5..760a786 100644 --- a/src/main/RdfMapper.ts +++ b/src/main/RdfMapper.ts @@ -18,12 +18,12 @@ export class RdfMapper { * @param type * @param ttlData */ - public static async deserializeAsync(type: { new(): T }, ttlData: string): Promise { + public static async deserializeAsync(type: { new(): T }, ttlData: string): Promise { const deserializeProcessor: DeserializerProcessor = new DeserializerProcessor(); return deserializeProcessor.deserializeAsync(type, ttlData); } - public static deserialize(type: { new(): T }, ttlData: string): T { + public static deserialize(type: { new(): T }, ttlData: string): T|T[] { const deserializeProcessor: DeserializerProcessor = new DeserializerProcessor(); return deserializeProcessor.deserialize(type, ttlData); } diff --git a/src/main/processors/DeserializerProcessor.ts b/src/main/processors/DeserializerProcessor.ts index bb79077..7fefcbf 100644 --- a/src/main/processors/DeserializerProcessor.ts +++ b/src/main/processors/DeserializerProcessor.ts @@ -31,7 +31,7 @@ export class DeserializerProcessor { constructor() {} - public async deserializeAsync(type: { new(): T }, ttlData: string): Promise { + public async deserializeAsync(type: { new(): T }, ttlData: string): Promise { let qa: QuadsAndPrefixes; try { qa = await this.getQuadsAndPrefixes(ttlData); @@ -45,13 +45,13 @@ export class DeserializerProcessor { } } - public deserialize(type: { new(): T }, ttlData: string): T { + public deserialize(type: { new(): T }, ttlData: string): T|T[] { let qs: Quad[]; try { qs = this.getQuads(ttlData); const store: N3Store = new Store(); store.addQuads(qs); - const dtoInstance: T = this.process(type, store); + const dtoInstance: T|T[] = this.process(type, store); return dtoInstance; } catch (e) { throw new TurtleParseError(e); @@ -133,8 +133,7 @@ export class DeserializerProcessor { return dtoInstance; } - private process(type: { new(): T }, store: N3Store, object?: Quad_Object): T { - const dtoInstance = new type(); + private process(type: { new(): T }, store: N3Store, object?: Quad_Object): T|T[] { const ns: IRdfPrefixes = Reflect.getMetadata('RdfPrefixes', type.prototype); const beanType: string = Reflect.getMetadata('RdfBean', type.prototype); @@ -142,8 +141,8 @@ export class DeserializerProcessor { const subject: IRdfSubjectMetadata = Reflect.getMetadata('RdfSubject-non-instance', type.prototype); const numTriples: Quad[] = this.getNumTriplesByBeanType(beanType, store, ns); - if (numTriples.length > 0) { - const triple: Quad = numTriples[0]; + const dtoInstances = numTriples.map((triple: Quad) => { + const dtoInstance = new type(); // Get URI and set the value for key which contains @RdfSubject annotation if (subject) { dtoInstance[subject.key] = Utils.getUUIDFromResourceSubject(triple.subject.value, subject.prop, ns); @@ -184,11 +183,15 @@ export class DeserializerProcessor { } } }); + return dtoInstance; + }) + if (numTriples.length === 1) { + return dtoInstances[0] + } else { + return dtoInstances } - return dtoInstance; - } private processPrimitiveByXSDType(value: string, xsdType: string): any { diff --git a/src/test/deserialize.spec.ts b/src/test/deserialize.spec.ts index adfd64d..0a8208e 100644 --- a/src/test/deserialize.spec.ts +++ b/src/test/deserialize.spec.ts @@ -1,5 +1,5 @@ import {RdfMapper} from '../main/RdfMapper'; -import {Person, personTTL, recipeVideoTTL} from './models/models'; +import {Person, personsTTL, personTTL, recipeVideoTTL} from './models/models'; import {oneToOneRelationship, PersonHasAddress} from './models/oneToOneModels'; import {Recipe, Video} from './models/recipes'; @@ -14,7 +14,7 @@ function logResult(assertName: string, result: any, logOnlyMe = false) { describe('Test TTL Deserialization', () => { it('Deserialize basic ttl (async)', async (done) => { - const instance: Person = await RdfMapper.deserializeAsync(Person, personTTL); + const instance: Person = await RdfMapper.deserializeAsync(Person, personTTL) as Person; // console.log(JSON.stringify(instance)); expect(instance.firstName).toEqual('David'); @@ -28,7 +28,7 @@ describe('Test TTL Deserialization', () => { }); it('Deserialize basic ttl', () => { - const instance: Person = RdfMapper.deserialize(Person, personTTL); + const instance: Person|Person[] = RdfMapper.deserialize(Person, personTTL) as Person; // console.log(JSON.stringify(instance)); expect(instance.firstName).toEqual('David'); @@ -39,8 +39,28 @@ describe('Test TTL Deserialization', () => { expect(instance.title).toEqual('Mr'); }); + it('Deserialize basic ttl with more than one instance', () => { + const instance: Person|Person[] = RdfMapper.deserialize(Person, personsTTL); + // console.log(JSON.stringify(instance)); + expect(typeof instance).toEqual('array'); + + expect(instance[0].firstName).toEqual('David'); + expect(instance[0].uuid).toEqual('1234567'); + expect(instance[0].name).toEqual('David Banner'); + expect(instance[0].nick).toEqual('hulk'); + expect(instance[0].surname).toEqual('Banner'); + expect(instance[0].title).toEqual('Mr'); + + expect(instance[1].firstName).toEqual('Sally'); + expect(instance[1].uuid).toEqual('7654321'); + expect(instance[1].name).toEqual('Sally Flickard'); + expect(instance[1].nick).toEqual('punchy'); + expect(instance[1].surname).toEqual('Flickard'); + expect(instance[1].title).toEqual('Ms'); + }); + it('Deserialize ttl with one-to-one relationship (async)', async (done) => { - const instance: PersonHasAddress = await RdfMapper.deserializeAsync(PersonHasAddress, oneToOneRelationship); + const instance: PersonHasAddress = await RdfMapper.deserializeAsync(PersonHasAddress, oneToOneRelationship) as PersonHasAddress; expect(instance.uuid).toEqual('person-uuid'); expect(instance.name).toEqual('John'); expect(instance.address.uuid).toEqual('address-uuid'); @@ -49,7 +69,7 @@ describe('Test TTL Deserialization', () => { }); it('Deserialize ttl with one-to-one relationship', () => { - const instance: PersonHasAddress = RdfMapper.deserialize(PersonHasAddress, oneToOneRelationship); + const instance: PersonHasAddress = RdfMapper.deserialize(PersonHasAddress, oneToOneRelationship) as PersonHasAddress; expect(instance.uuid).toEqual('person-uuid'); expect(instance.name).toEqual('John'); expect(instance.address.uuid).toEqual('address-uuid'); @@ -57,7 +77,7 @@ describe('Test TTL Deserialization', () => { }); it('Deserialize blank nodes (async)', async (done) => { - const recipe: Recipe = await RdfMapper.deserializeAsync(Recipe, recipeVideoTTL); + const recipe: Recipe = await RdfMapper.deserializeAsync(Recipe, recipeVideoTTL) as Recipe; expect(recipe instanceof Recipe).toBeTruthy(); expect(recipe.video).toBeDefined(); expect(recipe.video instanceof Video).toBeTruthy(); @@ -68,7 +88,7 @@ describe('Test TTL Deserialization', () => { }); it('Deserialize blank nodes', () => { - const recipe: Recipe = RdfMapper.deserialize(Recipe, recipeVideoTTL); + const recipe: Recipe = RdfMapper.deserialize(Recipe, recipeVideoTTL) as Recipe; expect(recipe instanceof Recipe).toBeTruthy(); expect(recipe.video).toBeDefined(); expect(recipe.video instanceof Video).toBeTruthy(); diff --git a/src/test/dieGracefully.spec.ts b/src/test/dieGracefully.spec.ts index ad80673..47c5dfb 100644 --- a/src/test/dieGracefully.spec.ts +++ b/src/test/dieGracefully.spec.ts @@ -16,7 +16,7 @@ function logResult(assertName: string, result: any) { describe('Meaningful Exceptions should be thrown', () => { it('Should throw TurtleParseError when turtle is invalid', async (done) => { try { - const instance: Person = await RdfMapper.deserializeAsync(Person, invalidTTL); + const instance: Person|Person[] = await RdfMapper.deserializeAsync(Person, invalidTTL); } catch (e) { expect(e instanceof TurtleParseError).toBeTruthy(); expect(e.name).toEqual('TurtleParseError');