Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/production' into hotfix-commits-…
Browse files Browse the repository at this point in the history
…fixes
  • Loading branch information
daneryl committed Sep 23, 2024
2 parents fadb484 + c3017b2 commit 5ad02ec
Show file tree
Hide file tree
Showing 9 changed files with 328 additions and 12 deletions.
8 changes: 6 additions & 2 deletions app/api/entities.v2/contracts/EntitiesDataSource.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ResultSet } from 'api/common.v2/contracts/ResultSet';
import { Entity, MetadataValue } from '../model/Entity';
import { Entity, EntityMetadata, MetadataValue } from '../model/Entity';

type MarkAsChangedCriteria = { template: string } | { sharedId: string };
type MarkAsChangedData = { property: string } | { properties: string[] };
Expand All @@ -8,7 +8,11 @@ export type MarkAsChangedItems = MarkAsChangedCriteria & MarkAsChangedData;
export interface EntitiesDataSource {
updateObsoleteMetadataValues(
id: Entity['_id'],
values: Record<string, MetadataValue[]>
values: Record<string, EntityMetadata[]>
): Promise<void>;
updateMetadataValues(
id: Entity['_id'],
values: Record<string, { value: MetadataValue }[]>
): Promise<void>;
entitiesExist(sharedIds: string[]): Promise<boolean>;
getByIds(sharedIds: string[], language?: string): ResultSet<Entity>;
Expand Down
28 changes: 25 additions & 3 deletions app/api/entities.v2/database/MongoEntitiesDataSource.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { ResultSet } from 'api/common.v2/contracts/ResultSet';
import { MongoDataSource } from 'api/common.v2/database/MongoDataSource';
import { MongoIdHandler } from 'api/common.v2/database/MongoIdGenerator';
import { MongoResultSet } from 'api/common.v2/database/MongoResultSet';
import { MongoTransactionManager } from 'api/common.v2/database/MongoTransactionManager';
import { MongoIdHandler } from 'api/common.v2/database/MongoIdGenerator';
import entities from 'api/entities/entities';
import { MongoSettingsDataSource } from 'api/settings.v2/database/MongoSettingsDataSource';
import { MongoTemplatesDataSource } from 'api/templates.v2/database/MongoTemplatesDataSource';
import { Db } from 'mongodb';
import { EntitiesDataSource } from '../contracts/EntitiesDataSource';
import { Entity, EntityMetadata, MetadataValue } from '../model/Entity';
import { EntityMappers } from './EntityMapper';
import { EntityDBO, EntityJoinTemplate } from './schemas/EntityTypes';
import { Entity, MetadataValue } from '../model/Entity';

export class MongoEntitiesDataSource
extends MongoDataSource<EntityDBO>
Expand Down Expand Up @@ -123,9 +124,30 @@ export class MongoEntitiesDataSource
return new MongoResultSet(result, entity => entity.sharedId);
}

// eslint-disable-next-line class-methods-use-this
async updateMetadataValues(
id: Entity['_id'],
values: Record<string, { value: MetadataValue }[]>
) {
// This is using V1 so that it gets denormalized to speed up development
// this is a hack and should be changed as soon as we finish AT
const entityToModify = await entities.getById(id);
if (!entityToModify) {
throw new Error(`entity does not exists: ${id}`);
}

Object.entries(values).forEach(([propertyName, metadataValues]) => {
entityToModify.metadata = entityToModify.metadata || {};
// @ts-ignore
entityToModify.metadata[propertyName] = metadataValues;
});

await entities.save(entityToModify, { user: {}, language: entityToModify.language });
}

async updateObsoleteMetadataValues(
id: Entity['_id'],
values: Record<string, MetadataValue[]>
values: Record<string, EntityMetadata[]>
): Promise<void> {
const stream = this.createBulkStream();

Expand Down
11 changes: 7 additions & 4 deletions app/api/entities.v2/model/Entity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
type MetadataValue = unknown;

type BaseMetadataValue = {
value: unknown;
value: MetadataValue;
label: string;
};

Expand All @@ -8,9 +10,9 @@ type InheritedResultValue = BaseMetadataValue & {
inheritedType: string;
};

type MetadataValue = BaseMetadataValue | InheritedResultValue;
type EntityMetadata = BaseMetadataValue | InheritedResultValue;

type Metadata = Record<string, MetadataValue[]>;
type Metadata = Record<string, EntityMetadata[]>;

export class Entity {
readonly _id: string;
Expand Down Expand Up @@ -45,4 +47,5 @@ export class Entity {
this.obsoleteMetadata = obsoleteMetadata ?? [];
}
}
export type { Metadata, MetadataValue };

export type { Metadata, EntityMetadata, MetadataValue };
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Template } from 'api/templates.v2/model/Template';
import { RelationshipProperty } from 'api/templates.v2/model/RelationshipProperty';
import { RelationshipsDataSource } from 'api/relationships.v2/contracts/RelationshipsDataSource';
import { TemplatesDataSource } from 'api/templates.v2/contracts/TemplatesDataSource';
import { Entity, MetadataValue } from '../model/Entity';
import { Entity, EntityMetadata } from '../model/Entity';
import { EntitiesDataSource } from '../contracts/EntitiesDataSource';

export class EntityRelationshipsUpdateService {
Expand Down Expand Up @@ -40,7 +40,7 @@ export class EntityRelationshipsUpdateService {
private async transformToDenormalizedData(
property: RelationshipProperty,
queryResult: Entity[]
): Promise<MetadataValue[]> {
): Promise<EntityMetadata[]> {
return Promise.all(
queryResult.map(async entity => ({
value: entity.sharedId,
Expand All @@ -65,7 +65,7 @@ export class EntityRelationshipsUpdateService {
await this.entitiesDataSource.getByIds(sharedIds).forEach(async entity => {
template = await this.findTemplate(template, entity.template);

const metadataToUpdate: Record<string, MetadataValue[]> = {};
const metadataToUpdate: Record<string, EntityMetadata[]> = {};

await Promise.all(
template.properties.map(async property => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { EntitiesDataSource } from 'api/entities.v2/contracts/EntitiesDataSource';
import { TemplatesDataSource } from 'api/templates.v2/contracts/TemplatesDataSource';
import { ATTranslationResultValidator } from './contracts/ATTranslationResultValidator';
import { InvalidInputDataFormat } from './errors/generateATErrors';
import { TranslationResult } from './types/TranslationResult';

export class SaveEntityTranslations {
static AITranslatedText = '(AI translated)';

private entitiesDS: EntitiesDataSource;

private templatesDS: TemplatesDataSource;

private validator: ATTranslationResultValidator;

constructor(
templatesDS: TemplatesDataSource,
entitiesDS: EntitiesDataSource,
validator: ATTranslationResultValidator
) {
this.entitiesDS = entitiesDS;
this.templatesDS = templatesDS;
this.validator = validator;
}

async execute(translationResult: TranslationResult | unknown) {
if (!this.validator.validate(translationResult)) {
throw new InvalidInputDataFormat(this.validator.getErrors()[0]);
}

const [, entitySharedId, propertyId] = translationResult.key;

const property = await this.getProperty(entitySharedId, propertyId);

const entities = this.entitiesDS.getByIds([entitySharedId]);

await entities.forEach(async oneEntity => {
const translation = translationResult.translations.find(
t => t.language === oneEntity.language
);
if (translation) {
await this.entitiesDS.updateMetadataValues(oneEntity._id, {
[property.name]: [
{ value: `${SaveEntityTranslations.AITranslatedText} ${translation.text}` },
],
});
}
});
}

private async getProperty(entitySharedId: string, propertyId: string) {
const entity = await this.entitiesDS.getByIds([entitySharedId]).first();
if (!entity) {
throw new Error('Entity does not exists');
}

const template = await this.templatesDS.getById(entity.template);
if (!template) {
throw new Error('Template does not exists');
}

const property = template.properties.find(p => p.id === propertyId);

if (!property) {
throw new Error('Property does not exists');
}
return property;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { TranslationResult } from '../types/TranslationResult';

export interface ATTranslationResultValidator {
getErrors(): string[];
validate(data: unknown): data is TranslationResult;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Ajv } from 'ajv';
import { JTDSchemaType } from 'ajv/dist/core';
import { TranslationResult } from '../types/TranslationResult';
import { ATTranslationResultValidator } from '../contracts/ATTranslationResultValidator';

const schema: JTDSchemaType<TranslationResult> = {
additionalProperties: false,
properties: {
key: { elements: { type: 'string' } },
text: { type: 'string' },
language_from: { type: 'string' },
languages_to: { elements: { type: 'string' } },
translations: {
elements: {
properties: {
text: { type: 'string' },
language: { type: 'string' },
success: { type: 'boolean' },
error_message: { type: 'string' },
},
},
},
},
};

export class AJVTranslationResultValidator implements ATTranslationResultValidator {
private errors: string[] = [];

getErrors() {
return this.errors;
}

validate(data: unknown) {
const ajv = new Ajv({ strict: false });
const validate = ajv.compile<TranslationResult>(schema);
const result = validate(data);
this.errors = validate.errors ? validate.errors?.map(e => JSON.stringify(e.params)) : [];
return result;
}
}
Loading

0 comments on commit 5ad02ec

Please sign in to comment.