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

feat: required fields #35

Merged
merged 2 commits into from
Feb 13, 2024
Merged

Conversation

ffMathy
Copy link
Contributor

@ffMathy ffMathy commented Feb 10, 2024

Supersedes #34.

I am a bit unsure if arrays are always set. I mean, it certainly makes sense to me, but I am not sure how the Ftrack API handles it. In my opinion, arrays should never be null or undefined, but instead empty. Let me know if this behavior does not reflect what's actually happening.

  • I have added automatic tests where applicable
  • The PR title is suitable as a release note
  • The PR contains a description of what has been changed
  • The description contains manual test instructions

Changes

Test

@ffMathy ffMathy requested a review from a team as a code owner February 10, 2024 15:35
@ffMathy ffMathy mentioned this pull request Feb 10, 2024
4 tasks
@ffMathy
Copy link
Contributor Author

ffMathy commented Feb 12, 2024

Callin' @jimmycallin ❤️

@jimmycallin
Copy link
Contributor

jimmycallin commented Feb 12, 2024

I'm of two minds around this and will need to sleep on this a bit.

Queries

Take this query for instance:

session.query<Task>("select id from Task limit 1");

Here I will get back an object saying that name will be available, which isn't true. What the required field really means is that if you ask for a value back, it won't be null. For this case, I think we should only list the primary keys as non-optional. To mark more fields as non-optional based on the expression, I can see us providing a generic that helps with this, something like:

type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] }

session.query<WithRequired<Task, "name">>("select name from Task limit 1");

Mutations

Thinking about it a bit more, I'm uncertain even if primary_key should be part of non-optional fields. It makes sense from a query standpoint, but take this update action for instance:

session.create<Task>("Task", [id], { name: "Test" } );

Here, I expect data to not need an entity key, as it will be generated if omitted. I don't even need all required fields, as some of them will have a default value on creation. Unfortunately we don't have a way in our schema today to see which fields are necessary to provide on creation or not.

Even further, when we have update events:

session.update<Task>("Task", [id], { status_id: "1234" });

I don't even need fields that are necessary for creation, as it is more like a PATCH event.

Looking at graphql, they split out Input types from query types, so perhaps the solution is to do something similar here and introduce TaskInput etc for mutations. In that case we can ignore the mutation questions above for now.

Just loose thoughts :) Let me know if you have any ideas!

@ffMathy
Copy link
Contributor Author

ffMathy commented Feb 13, 2024

Here I will get back an object saying that name will be available, which isn't true. What the required field really means is that if you ask for a value back, it won't be null. For this case, I think we should only list the primary keys as non-optional.

Indeed, but as I mentioned in my other PR, I think it should be the Ftrack API's responsibility to wrap the type in a Partial instead.

The type should represent the truth of the datamodel. The fact that some fields may not be required is specific to the call that the Ftrack client makes, and hence, the partial should be in its return type instead. For instance:

class ApiClient {
  function create<T>(foo: T): Partial<T> { ... } //now even if some fields in T are required, they are optional in this case
}

Here, I expect data to not need an entity key, as it will be generated if omitted. I don't even need all required fields, as some of them will have a default value on creation. Unfortunately we don't have a way in our schema today to see which fields are necessary to provide on creation or not.

Again, same applies here. It should be the responsibility of the create method's type to wrap that in a partial.

I don't even need fields that are necessary for creation, as it is more like a PATCH event.

Same answer here.

Those are my thoughts. In my opinion, we're breaking the encapsulation principle by defining types that are actually not what the data represents, but instead represent how they look when they are used.

A class should not be able to know how it is used. That violates that principle.

@jimmycallin
Copy link
Contributor

that makes a lot of sense! thanks for explaining your thoughts. i think we can merge this and try it out :)

@jimmycallin jimmycallin merged commit f079095 into ftrackhq:main Feb 13, 2024
1 check failed
@ffMathy
Copy link
Contributor Author

ffMathy commented Feb 13, 2024

Great stuff! ❤️ When will it typically be released? 🙏

@jimmycallin
Copy link
Contributor

Great stuff! ❤️ When will it typically be released? 🙏

i have already created a 2.0.0-beta.1, try it out!

@ffMathy
Copy link
Contributor Author

ffMathy commented Feb 13, 2024

Ah okay - I think we'll wait until it's out of beta ❤️

@ffMathy
Copy link
Contributor Author

ffMathy commented Feb 14, 2024

Nevermind, had some time to spare. We're now on the beta and all our tests pass, and the types look great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants