diff --git a/lib/model/query/entities.js b/lib/model/query/entities.js index 9fb4d0703..1b62581e9 100644 --- a/lib/model/query/entities.js +++ b/lib/model/query/entities.js @@ -184,8 +184,7 @@ const createVersion = (dataset, entity, data, label, sourceId, userAgentIn = nul select ${_unjoiner.fields} from def as entity_defs join entities on entity_defs."entityId" = entities.id `) - .then(_unjoiner) - .then((e) => e.withAux('currentVersion', e.aux.currentVersion)); + .then(_unjoiner); }; createVersion.audit = (newEntity, dataset, entity) => (log) => @@ -232,16 +231,18 @@ const _get = (includeSource) => { `); }; +const assignCurrentVersionCreator = (entity) => { + const currentVersion = new Entity.Def(entity.aux.currentVersion, { creator: entity.aux.currentVersionCreator }); + return new Entity(entity, { currentVersion, creator: entity.aux.creator }); +}; + const getById = (datasetId, uuid, options = QueryOptions.none) => ({ maybeOne }) => _get(true)(maybeOne, options.withCondition({ datasetId, uuid }), isTrue(options.argData?.deleted)) - .then(map((entity) => { - const currentVersion = new Entity.Def(entity.aux.currentVersion, { creator: entity.aux.currentVersionCreator }); - return new Entity(entity, { currentVersion, creator: entity.aux.creator }); - })); + .then(map(assignCurrentVersionCreator)); const getAll = (datasetId, options = QueryOptions.none) => ({ all }) => _get(false)(all, options.withCondition({ datasetId }), isTrue(options.argData.deleted)) - .then(map((e) => e.withAux('currentVersion', e.aux.currentVersion.withAux('creator', e.aux.currentVersionCreator)))); + .then(map(assignCurrentVersionCreator)); //////////////////////////////////////////////////////////////////////////////// // GETTING ENTITY DEFS diff --git a/test/integration/api/entities.js b/test/integration/api/entities.js index 6deb8f6e7..74276484e 100644 --- a/test/integration/api/entities.js +++ b/test/integration/api/entities.js @@ -124,6 +124,45 @@ describe('Entities API', () => { }); }); })); + + it('should not mince the object properties', testEntities(async (service, container) => { + const asAlice = await service.login('alice'); + const asBob = await service.login('bob'); + + await asBob.patch('/v1/projects/1/datasets/people/entities/12345678-1234-4123-8234-123456789abc?force=true') + .send({ label: 'two' }) + .expect(200); + + await container.run(sql`UPDATE actors SET "createdAt" = '2020-01-01' WHERE "displayName" = 'Alice'`); + await container.run(sql`UPDATE actors SET "createdAt" = '2021-01-01' WHERE "displayName" = 'Bob'`); + + await container.run(sql`UPDATE entities SET "createdAt" = '2022-01-01', "updatedAt" = '2023-01-01' WHERE uuid = '12345678-1234-4123-8234-123456789abc'`); + + await container.run(sql`UPDATE entity_defs SET "createdAt" = '2022-01-01' WHERE label = 'Alice (88)'`); + await container.run(sql`UPDATE entity_defs SET "createdAt" = '2023-01-01' WHERE label = 'two'`); + + await asAlice.get('/v1/projects/1/datasets/people/entities') + .set('X-Extended-Metadata', true) + .expect(200) + .then(({ body: people }) => { + people.forEach(p => { + p.should.be.an.ExtendedEntity(); + p.should.have.property('currentVersion').which.is.an.ExtendedEntityDef(); + }); + + const person = people.find(p => p.uuid === '12345678-1234-4123-8234-123456789abc'); + + person.createdAt.should.match(/2022/); + person.updatedAt.should.match(/2023/); + + person.creator.displayName.should.be.eql('Alice'); + person.creator.createdAt.should.match(/2020/); + + person.currentVersion.createdAt.should.match(/2023/); + person.currentVersion.creator.displayName.should.be.eql('Bob'); + person.currentVersion.creator.createdAt.should.match(/2021/); + }); + })); }); describe('GET /datasets/:name/entities/:uuid', () => { @@ -180,6 +219,46 @@ describe('Entities API', () => { }); })); + + it('should not mince the object properties', testEntities(async (service, container) => { + const asAlice = await service.login('alice'); + const asBob = await service.login('bob'); + + await asBob.patch('/v1/projects/1/datasets/people/entities/12345678-1234-4123-8234-123456789abc?force=true') + .send({ label: 'two' }) + .expect(200); + + await container.run(sql`UPDATE actors SET "createdAt" = '2020-01-01' WHERE "displayName" = 'Alice'`); + await container.run(sql`UPDATE actors SET "createdAt" = '2021-01-01' WHERE "displayName" = 'Bob'`); + + await container.run(sql`UPDATE entities SET "createdAt" = '2022-01-01', "updatedAt" = '2023-01-01'`); + + await container.run(sql`UPDATE entity_defs SET "createdAt" = '2022-01-01' WHERE label = 'Alice (88)'`); + await container.run(sql`UPDATE entity_defs SET "createdAt" = '2023-01-01' WHERE label = 'two'`); + + await asAlice.get('/v1/projects/1/datasets/people/entities/12345678-1234-4123-8234-123456789abc') + .set('X-Extended-Metadata', true) + .expect(200) + .then(({ body: person }) => { + person.should.be.an.ExtendedEntity(); + person.should.have.property('currentVersion').which.is.an.ExtendedEntityDef(); + person.currentVersion.should.have.property('data').which.is.eql({ + age: '88', + first_name: 'Alice' + }); + + person.createdAt.should.match(/2022/); + person.updatedAt.should.match(/2023/); + + person.creator.displayName.should.be.eql('Alice'); + person.creator.createdAt.should.match(/2020/); + + person.currentVersion.createdAt.should.match(/2023/); + person.currentVersion.creator.displayName.should.be.eql('Bob'); + person.currentVersion.creator.createdAt.should.match(/2021/); + }); + })); + it('should return full entity even if form+submission has been deleted and purged', testEntities(async (service, container) => { const asAlice = await service.login('alice');