Browse Source

add the HydraNormalizer service

Olivier Massot 2 years ago
parent
commit
b79edad475

+ 14 - 0
models/ApiResource.ts

@@ -6,6 +6,7 @@ import {Model} from "pinia-orm";
 export class ApiResource extends Model {
 
     private _model: typeof ApiResource | undefined = undefined;
+    static readonly relations: Record<string, ApiResource>
 
     public getModel() {
         return this._model
@@ -15,6 +16,10 @@ export class ApiResource extends Model {
         this._model = model
     }
 
+    public getRelations() {
+        return this.relations
+    }
+
     /**
      * Fix the 'Cannot stringify arbitrary non-POJOs' warning, meaning server can not parse the store
      *
@@ -32,6 +37,15 @@ export class ApiResource extends Model {
     public isNew(): boolean {
         return !this.id || (typeof this.id === 'string' && this.id.slice(0, 3) === 'tmp')
     }
+
+    /**
+     * Get the IRI of the Entity
+     *
+     * @see https://api-platform.com/docs/admin/handling-relations/
+     */
+    public getIRI() {
+        return `/api/${this.entity}/${this.id}`
+    }
 }
 
 export default ApiResource

+ 6 - 1
models/Organization/Parameters.ts

@@ -1,5 +1,7 @@
 import ApiModel from '~/models/ApiModel'
 import { Bool, Num, Str, Uid, Attr } from 'pinia-orm/dist/decorators'
+import Access from "~/models/Access/Access";
+import ApiResource from "~/models/ApiResource";
 
 /**
  * AP2i Model : Parameters
@@ -8,6 +10,9 @@ import { Bool, Num, Str, Uid, Attr } from 'pinia-orm/dist/decorators'
  */
 export default class Parameters extends ApiModel {
   static entity = 'parameters'
+  static readonly relations: Record<string, ApiResource> = {
+    publicationDirectors: Access
+  }
 
   @Uid()
   declare id: number | string | null
@@ -121,5 +126,5 @@ export default class Parameters extends ApiModel {
   declare subdomains: []
 
   @Bool(false, { notNullable: true })
-  declare notifyAdministrationAbsence: boolean 
+  declare notifyAdministrationAbsence: boolean
 }

+ 1 - 1
models/models.ts

@@ -4,7 +4,7 @@ import ApiResource from "~/models/ApiResource";
 const models: Record<string, typeof ApiResource> = {}
 
 for (const path in modules) {
-    modules[path]().then((mod) => {
+    modules[path]().then((mod: any) => {
         models[mod.default.entity] = mod.default
     })
 }

+ 1 - 1
package.json

@@ -78,7 +78,7 @@
     "jsdom": "^22.1.0",
     "prettier": "^2.8.4",
     "ts-jest": "^29.0.3",
-    "typescript": "4.9.5",
+    "typescript": "^5.2",
     "vitest": "0.32.2",
     "vue-jest": "^3.0.7"
   }

+ 3 - 2
services/data/entityManager.ts

@@ -10,6 +10,7 @@ import {AssociativeArray, Collection} from "~/types/data.d"
 import models from "~/models/models";
 import {useAccessProfileStore} from "~/stores/accessProfile"
 import * as _ from "lodash-es"
+import HydraNormalizer from "~/services/data/normalizer/hydraNormalizer";
 
 /**
  * Entity manager: make operations on the models defined with the Pinia-Orm library
@@ -214,12 +215,12 @@ class EntityManager {
     public async persist(model: typeof ApiModel, instance: ApiModel) {
         // Recast in case class definition has been "lost"
         // TODO: attendre de voir si cette ligne est nécessaire
-        // instance = this.cast(model, instance)
+        instance = this.cast(model, instance)
 
         let url = UrlUtils.join('api', model.entity)
         let response
 
-        const data: any = instance.$toJson()
+        const data: any = HydraNormalizer.normalizeEntity(instance)
 
         if (!instance.isNew()) {
             url = UrlUtils.join(url, String(instance.id))

+ 1 - 1
services/data/normalizer/hydraDenormalizer.ts

@@ -3,7 +3,7 @@ import UrlUtils from '~/services/utils/urlUtils'
 import {METADATA_TYPE} from '~/types/enum/data'
 
 /**
- * Normalisation et dé-normalisation ddu format de données Hydra
+ * Dénormalisation du format de données Hydra
  */
 class HydraDenormalizer {
 

+ 37 - 0
services/data/normalizer/hydraNormalizer.ts

@@ -0,0 +1,37 @@
+import {AnyJson} from "~/types/data";
+import ApiResource from "~/models/ApiResource";
+import {isArray, isNumber} from "lodash";
+import UrlUtils from "~/services/utils/urlUtils";
+
+/**
+ * Normalisation du format de données Hydra
+ */
+class HydraNormalizer {
+    public static normalizeEntity(entity: ApiResource): AnyJson {
+
+        const prototype = Object.getPrototypeOf(entity)
+        const relations = prototype.constructor.relations
+
+        for (const field in relations) {
+            const value = entity[field]
+
+            if (!isArray(value)) {
+                console.warn("A model's relation is not an array")
+                continue
+            }
+
+            const targetEntity = relations[field].entity
+
+            entity[field] = value.map((id: number | string) => {
+                if (!isNumber(id)) {
+                    throw Error(field + ' : invalid id')
+                }
+                return UrlUtils.makeIRI(targetEntity, id)
+            })
+        }
+
+        return entity.$toJson()
+    }
+}
+
+export default HydraNormalizer

+ 9 - 0
services/utils/urlUtils.ts

@@ -126,6 +126,15 @@ class UrlUtils {
 
     return result
   }
+
+  /**
+   * Make an ApiPlatform IRI for the given entity and id
+   *
+   * @see https://api-platform.com/docs/admin/handling-relations/
+   */
+  public static makeIRI(entity: string, id: number) {
+    return `/api/${entity}/${id}`
+  }
 }
 
 export default UrlUtils

+ 4 - 4
yarn.lock

@@ -8777,10 +8777,10 @@ typed-array-length@^1.0.4:
     for-each "^0.3.3"
     is-typed-array "^1.1.9"
 
-typescript@4.9.5:
-  version "4.9.5"
-  resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
-  integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
+typescript@^5.2:
+  version "5.2.2"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78"
+  integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==
 
 ufo@^1.0.0, ufo@^1.1.0, ufo@^1.1.1, ufo@^1.1.2:
   version "1.1.2"