Skip to content

Instantly share code, notes, and snippets.

@Nifled
Last active July 5, 2023 00:09
Show Gist options
  • Save Nifled/6183d4f965831f90a9a2d189164792ff to your computer and use it in GitHub Desktop.
Save Nifled/6183d4f965831f90a9a2d189164792ff to your computer and use it in GitHub Desktop.

Revisions

  1. Nifled revised this gist Jul 5, 2023. No changes.
  2. Nifled revised this gist Mar 16, 2023. No changes.
  3. Nifled revised this gist Mar 16, 2023. 2 changed files with 4 additions and 3 deletions.
    5 changes: 3 additions & 2 deletions BaseModel.ts
    Original file line number Diff line number Diff line change
    @@ -7,19 +7,20 @@
    public toJSON(): any {
    const proto = Object.getPrototypeOf(this);
    const jsonObj = {
    [NModel.serializedUmtKey]: proto.constructor.universalModelType()
    [BaseModel.umt]: proto.constructor.universalModelType()
    };

    // Tterate through whole prototype chain (all the way to Object)
    for (let o = this; o !== Object.prototype; o = Object.getPrototypeOf(o)) {
    // Iterate through all properties of given object prototype
    for (const name of Object.getOwnPropertyNames(o)) {
    const descriptor = Object.getOwnPropertyDescriptor(o, name);

    if (typeof descriptor!.get === 'function') {
    // instead of getting from `o`, get from `this`,
    // since `o` is now the prototype of a superclass
    const val = (this as any)[name];
    const serializedVal = this.jsonReplacerForProperty(val);
    const serializedVal = transFormPropertytoJSON(val);

    jsonObj[name] = serializedVal;
    }
    2 changes: 1 addition & 1 deletion gistfile1.txt → utils.ts
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@
    * Transform special BaseModel properties (Set, UUID, Date, etc) to JSON-compatible stringified object properties
    * @param property object property definition
    */
    private transFormPropertytoJSON(property: any): any {
    function transFormPropertytoJSON(property: any): any {
    if (property instanceof UUID) {
    return property.toString();
    } else if (property instanceof Date) {
  4. Nifled created this gist Mar 16, 2023.
    33 changes: 33 additions & 0 deletions BaseModel.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,33 @@
    // ...... other BaseModel code

    /**
    * Recursively serialize properties through class getters
    * Returns ready object for JSON.stringify()
    */
    public toJSON(): any {
    const proto = Object.getPrototypeOf(this);
    const jsonObj = {
    [NModel.serializedUmtKey]: proto.constructor.universalModelType()
    };

    // Tterate through whole prototype chain (all the way to Object)
    for (let o = this; o !== Object.prototype; o = Object.getPrototypeOf(o)) {
    // Iterate through all properties of given object prototype
    for (const name of Object.getOwnPropertyNames(o)) {
    const descriptor = Object.getOwnPropertyDescriptor(o, name);
    if (typeof descriptor!.get === 'function') {
    // instead of getting from `o`, get from `this`,
    // since `o` is now the prototype of a superclass
    const val = (this as any)[name];
    const serializedVal = this.jsonReplacerForProperty(val);

    jsonObj[name] = serializedVal;
    }
    }
    }

    return jsonObj;
    }


    // ...... other BaseModel code
    40 changes: 40 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,40 @@
    This is a snippet of code from a project I proposed to my team that was going to automate processes relating
    to serialization and deserialization of objects sent between our clients (web, desktop, ios, android, macos).
    All of our web and desktop clients were JS based and each of them included an individual implementation for
    serializing objects received from other clients. I proposed a library to abstract all of that logic away from
    the clients and also avoid having to modify code in every client when a change was needed.

    This piece of code is related to deserialization of objects.

    A lot of our objects (models) inherited from `BaseModel` and most of these objects made use of data structures or types
    that weren't compatible with JSON. If we had an object like this:
    ```js
    const object = {
    items: new Set([1, 2, 3, 4, 5]),
    date: new Date(),
    id: new UUID(), // custom internal class
    somNestedObject: {
    items: new Set([6, 7, 8, 9])
    }
    };
    ```
    This object isn't straighforward to `JSON.stringify()`, since JSON is only compatible with objects and general data
    types like arrays, numbers, strings and booleans. With the previous code, the `stringify()` call evaluates to something like:
    ```
    "
    {
    "items": {},
    "date": "2023-03-16T22:52:14.111Z",
    id: {},
    somNestedObject: {
    items: {}
    }
    }
    "
    ```
    As you can see, this is not what we wanted at all. So the code based on this gist is what basically automates this for
    any type of object that inherits `BaseModel` and it goes through all the the defined properties (with getters)
    and transform the type to a compatible one (EG `items: new Set([1, 2, 3, 4, 5])` -> `items: [1, 2, 3, 4, 5]`). It pretty
    much gets it ready for "stringifying".


    19 changes: 19 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,19 @@
    /**
    * Transform special BaseModel properties (Set, UUID, Date, etc) to JSON-compatible stringified object properties
    * @param property object property definition
    */
    private transFormPropertytoJSON(property: any): any {
    if (property instanceof UUID) {
    return property.toString();
    } else if (property instanceof Date) {
    return property.getTime(); // epoch time
    } else if (property instanceof BaseModel) {
    // Account for any nested models
    return property.toJSON();
    } else if (property instanceof Set) {
    // There are no Sets in JSON so we need some form of mapping
    // Also, call this func recursively on any nested models
    return [...property].map(p => transFormPropertytoJSON(p));
    }
    return property;
    }