Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Find better way to support empty constructor and constructor with arguments #67

Open
tobiasschweizer opened this issue Sep 26, 2019 · 6 comments
Assignees
Labels
enhancement Improve existing code or new feature
Milestone

Comments

@tobiasschweizer
Copy link
Contributor

tobiasschweizer commented Sep 26, 2019

Currently, complex values like ReadDateValue or ReadGeomValue are instantiated in two steps: first, json2typescript creates an instance of ParseReadDateValue or ParseReadGeomValue, respectively. From this, a ReadDateValue or ReadGeomValue is constructed. All classes are subclasses of ReadValue and therefore we need to support two constructor signatures: an empty and a non-empty one:

https://github.com/dhlab-basel/knora-api-js-lib/blob/4bbfa88e95e351662e2e3e171d625d8ae96bc338/src/models/v2/resources/values/read-value.ts#L42-L66

The solution was to make every parameter optional. But this is error prone, see #66.

@tobiasschweizer tobiasschweizer added the enhancement Improve existing code or new feature label Sep 26, 2019
@tobiasschweizer
Copy link
Contributor Author

@andreas-aeschlimann
Copy link
Contributor

I usually use static methods to overload:

static createInstanceFromSomething(id: string, type: string, ...): ReadValue {
    const readValue = new ReadValue();
    readValue.id = id;
    readValue.type = type;
    ...
    return readValue;
}

@tobiasschweizer
Copy link
Contributor Author

@andreas-aeschlimann Thanks, I will try out factory methods after my holidays!

@andreas-aeschlimann
Copy link
Contributor

andreas-aeschlimann commented Oct 24, 2019

Problem: The class generated by Knora defines an empty constructor because of json2typescript. This could lead to the creation of – in view of the backend – invalid instances.

Solution: Provide a protected constructor and define a static factory method with all properties that are required by the backend to have a consistent instance.

protected constructor() {}

static createInstanceFromSomething(firstName: string, lastName: string): User {
   
    const instance = new User();
   
    // Set all properties that are required in terms of the backend to have a complete instance
    instance.firstName = firstName
    instance.lastName = lastName;
   
    // Create a consistency method that checks the current state of the class
    instance.checkConsistency();

    return instance;

}

Furthermore, the consistency checks could be in a method that always look the same:

checkConsistency(): void {
    if (this.lastName.length > 0 && this.firstName.length === 0) {
        throw new Error("User must have a firstName if it has a lastName");
    }
}

If we also need checks on specific properties, I suggest that we use getters and setters as follows:

@JsonConvert("firstName", String); // the decorator must be assigned to the private property
private _firstName: string = "";
get firstName(): string { return this._firstName; }
set firstName(value: string) {
    if (value === "root") {
        throw new Error("First name must not be root");
    }
    this._firstName = value;
}

The frontend has different needs as the backend and therefore should be able to easily extend these classes. For example, if we need stricter consistency checks or deeper checks in setters, we can still extend a class and implement this.

In any case that we want to adjust a class on the client, we will need to extend it anyway. It makes no sense to implement too much TypeScript through Knora.

@tobiasschweizer
Copy link
Contributor Author

Provide a protected constructor and define a static factory method with all properties that are required by the backend to have a consistent instance.

So there would be no way to call the empty constructor directly, but only via the public static method. I think that's a good approach.

The frontend has different needs as the backend and therefore should be able to easily extend these classes. For example, if we need stricter consistency checks or deeper checks in setters, we can still extend a class and implement this.

I like your idea. We would have to come up with a way to keep in sync with the Knora API. More properties could be added or their names could change.

I have added integrate-generated-files-admin.sh to make this easier for the admin API.

I think the proper way to do this is coordinating the releases with @subotic and add automated e2e test with an actual Knora, see https://github.com/dasch-swiss/knora-api-js-lib-test/blob/angular/.travis.yml.

In any case that we want to adjust a class on the client, we will need to extend it anyway. It makes no sense to implement too much TypeScript through Knora.

Yes, we should get all necessary information from Knora regarding the API's interface, but not more than that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Improve existing code or new feature
Projects
None yet
Development

No branches or pull requests

4 participants