4

Is it possible to write a TypeScript Function which programmatically creates copies of an object, without hardcoding references to the object properties being copied?

I'm trying to enable a user workflow where the user is empowered to create copies of a specified object, i.e. create and partially complete one object using a Form, create 10x duplicates of the new object, fill-in data for new objects.

I've succeeded in creating a Function-Backed Action which duplicates a designated object, but all references to the properties being copied are hardcoded, which is less than ideal for maintenance and is a relatively common request for our org.

Code example for desired Function:

@OntologyEditFunction()
public GenerticBatchCopyObjects(mySelectedObject: ObjectAPIName, numberNewObjects: Integer): void {
    /** Set UUID primary key */
    let object_pk = Uuid.random()

    for (let i = 1; i <= numberNewObjects; i++) {
        /** initialize new object */
        const newObject = Objects.create().ObjectAPIName(object_pk + "_" + String(i))

        /** copy all properties from selected object record to new object */
        for property in mySelectedObject.properties:
            if property != "name_of_primary_key_column":
                newObject.property = mySelectedObject.property 
    }
}
L99
  • 169
  • 9

1 Answers1

3

There’s not really a nice way to achieve this currently and it’s maybe not advised. This is primarily because the list of properties that will be copied from an object are fixed at publish-/compile-time in any (nice) method I can see.

Partial type-safe solution for copying properties only

I've included the most generic version of this function I can construct below, but it has some limitations. More concretely, the copy function

  1. does not copy links that aren't represented by FK properties (i.e. it only copies properties);
  2. does not adapt and might break when there are new or removed properties; and
  3. is not easily maintained as functionality can change depending on when it is compiled.
private isPrimaryKey(x: string): x is MyObjectType["primaryKey"]["apiName"] {
    return x === MyObjectType.primaryKey.apiName;
}

@OntologyEditFunction()
public copy(obj: MyObjectType): void {
    const new_obj = Objects.create().myObjectType(Uuid.random());
    var prop : keyof typeof MyObjectType.properties;
    for (prop in MyObjectType.properties) {
        if (!this.isPrimaryKey(prop)) {
            new_obj[prop] = obj[prop];
        }
    }
}

Explicit type-safe solution for copying everything

The approach below requires more manual adjustment if the ontology changes, but makes it explicit that the code must be changed in line with ontology changes. This approach also copies links.

It is also worth noting that this behaviour may not be desired behaviour because it doesn't recursively copy the linked objects and instead attempts to copy the links. Please test that this gives the desired results.

static PROPERTIES = ["myProperty"] as const;
static MULTILINKS = ["myMultiLink"] as const;
static SINGLELINKS = ["mySingleLink", "myOtherSingleLink"] as const;

@OntologyEditFunction()
public copy2(obj: MyObjectType): void {
    const new_obj = Objects.create().myObjectType(Uuid.random());
    MyFunctions.PROPERTIES.forEach(p => {
        new_obj[p] = obj[p];
    });
    MyFunctions.MULTILINKS.forEach(p => {
        obj[p].all().forEach(v => new_obj[p].add(v));
    });
    MyFunctions.SINGLELINKS.forEach(p => {
        const v = obj[p].get();
        if (v !== undefined) {
            new_obj[p].set(v);
        }
    });
}

You may need to exclude some of the code if your object type does not have properties/multi-links/single-links to make the compiler happy.

jlo
  • 113
  • 1
  • 5