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(repository-json-schema): add an option to make properties optional #3309

Merged
merged 2 commits into from
Jul 15, 2019

Conversation

nabdelgadir
Copy link
Contributor

@nabdelgadir nabdelgadir commented Jul 5, 2019

Add a new option optional: [] so that getJsonSchema and related helpers can request a model schema that marks specified properties as optional

Connect to #2653

Checklist

👉 Read and sign the CLA (Contributor License Agreement) 👈

  • npm test passes on your machine
  • New tests added or existing tests modified to cover all changes
  • Code conforms with the style guide
  • API Documentation in code was updated
  • Documentation in /docs/site was updated
  • Affected artifact templates in packages/cli were updated
  • Affected example projects in examples/* were updated

👉 Check out how to submit a PR 👈

}

it('makes one property optional when the option "optional" includes one property', () => {
const originalSchema = getJsonSchema(Product);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nabdelgadir A question for the generic type T in this PR: if you don't specify the type when calling getJsonSchema(ModelCtor), then where is it provided?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think TS 3.5.x defaults to unknown.

let suffix = '';
if (options.partial) {
suffix += 'Partial';
}
if (options.optional && options.optional.length) {
suffix += 'Optional[' + options.optional + ']';
}
if (options.includeRelations) {
suffix += 'WithRelations';
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be simpler to have the title as:

<originalModelName>:<stringified-json-for-options>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note the suffix is used in JSON/OpenAPI Schema titles. These titles are later used by code generators like swagger-codegen to emit interface or class names in TypeScript/Java/C#/etc.

While it may be easier for us to build the prefix as stringified json, I believe it will provide suboptimal experience for our users and anybody consuming OpenAPI spec generated by LB4 applications.

@@ -232,13 +232,27 @@ describe('build-schema', () => {
expect(key).to.equal('modelPartial');
});

it('returns concatenated option names otherwise', () => {
it('returns "optional[id,_rev]" when a single option "optional" is set', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test name is misleading, you are setting two properties as optional.

Suggested change
it('returns "optional[id,_rev]" when a single option "optional" is set', () => {
it('returns "optional[id,_rev]" when "optional" is set with two items', () => {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is supposed to mean only the optional option is set (similar to the partial test above it: returns "partial" when a single option "partial" is set'), but I'll reword this one.

const key = buildModelCacheKey({
// important: object keys are defined in reverse order
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please preserve this comment in the test it('returns concatenated option names otherwise', () => {

it('returns concatenated option names otherwise', () => {
const key = buildModelCacheKey({
partial: true,
optional: ['id', '_rev'],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When partial is set to true, the optional config is effectively ignored, because all properties are optional.

Should we tell the user that they are may be doing something wrong? Personally, I would throw an error if both partial and optional are set.

Regardless of the solution we choose, please add a test to verify what happens when both partial and optional are set.


On Slack, we discussed an alternative solution: instead of adding optional?: (keyof T)[];, we can modify partial to accept boolean | keyof T)[]. This removes the edge case where both optional and partial are set. My concern was that this solution may be more difficult to understand for our users.

Copy link
Contributor Author

@nabdelgadir nabdelgadir Jul 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I opted to use optional is because I felt the name partial might be confusing. If you set partial to [prop1, prop2] then it might make it seem like these are the only two properties required and the rest are optional. What do you think?

I'll modify the test based on the approach.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @nabdelgadir that partial: ['a', 'b'] can be misleading.

IMO, partial: true becomes a shortcut of optional to mark all properties optional. My intuitive interpretation is the more specific one wins, i.e., optional: ['a', 'b'] should override partial: true. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I think optional should override partial as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I think optional should override partial as well.

Makes sense 👍

I feel it's important to describe this rule in (API) docs and have a test to verify the behavior.

@nabdelgadir nabdelgadir force-pushed the optional-model-schema branch 2 times, most recently from d83d9e6 to 4cbaafd Compare July 11, 2019 17:44
"@types/json-schema": "^7.0.3"
"@types/json-schema": "^7.0.3",
"debug": "^4.1.1",
"@types/debug": "^4.1.4"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: it's good enough to be a dev dep.

);
});

it('doesn\'t make properties optional when the option "optional" includes no properties', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: we can use ` to quote the string to avoid escaping, such as:

`doesn't make properties optional when the option "optional" includes no properties`

@nabdelgadir nabdelgadir force-pushed the optional-model-schema branch from 4cbaafd to d28bb56 Compare July 15, 2019 15:22
Add a new option `optional: []` so that `getJsonSchema` and related helpers can request a model schema that marks specified properties as optional
@nabdelgadir nabdelgadir force-pushed the optional-model-schema branch from d28bb56 to 0e383fc Compare July 15, 2019 15:33
@nabdelgadir nabdelgadir merged commit 363a4b5 into master Jul 15, 2019
@delete-merged-branch delete-merged-branch bot deleted the optional-model-schema branch July 15, 2019 15:54
Copy link
Member

@bajtos bajtos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I think optional should override partial as well.

Makes sense 👍

I feel it's important to describe this rule in (API) docs and have a test to verify the behavior.

@nabdelgadir I see that you have included the test, that's great!

Can you please update the API docs to describe the precedence rule for partial and optional too? I think it would be best to mention it in API docs for both options.

expect(optionalNothingSchema.title).to.equal('Product');
});

it('overrides "partial" option when "optional" options is set', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

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

Successfully merging this pull request may close these issues.

4 participants