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

Review/update/fix query definitions #486

Merged
merged 2 commits into from
Jul 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions compiler/model/metamodel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,11 @@ export class Interface extends BaseType {
*/
attachedBehaviors?: string[]
properties: Property[]
/**
* The property that can be used as a shortcut for the entire data structure in the JSON.
*/
shortcutProperty?: string

/** Identify containers */
variants?: Container
}
Expand Down
12 changes: 10 additions & 2 deletions compiler/model/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import { dirname, sep } from 'path'
*/
export const knownBehaviors = [
'AdditionalProperties',
'AdditionalProperty',
'CommonQueryParameters',
'CommonCatQueryParameters'
]
Expand Down Expand Up @@ -228,7 +229,8 @@ export function modelType (node: Node): model.ValueOf {
return type
}

case 'SingleKeyDictionary': {
case 'SingleKeyDictionary':
case 'AdditionalProperty': {
assert(node, node.getTypeArguments().length === 2, 'A SingleKeyDictionary must have two arguments')
const [key, value] = node.getTypeArguments().map(node => modelType(node))
const type: model.DictionaryOf = {
Expand Down Expand Up @@ -549,7 +551,7 @@ export function hoistTypeAnnotations (type: model.TypeDefinition, jsDocs: JSDoc[
// We want to enforce a single jsDoc block.
assert(jsDocs, jsDocs.length < 2, 'Use a single multiline jsDoc block instead of multiple single line blocks')

const validTags = ['class_serializer', 'doc_url', 'behavior', 'variants', 'variant']
const validTags = ['class_serializer', 'doc_url', 'behavior', 'variants', 'variant', 'shortcut_property']
const tags = parseJsDocTags(jsDocs)
if (jsDocs.length === 1) {
const description = jsDocs[0].getDescription()
Expand All @@ -559,6 +561,12 @@ export function hoistTypeAnnotations (type: model.TypeDefinition, jsDocs: JSDoc[
setTags(jsDocs, type, tags, validTags, (tags, tag, value) => {
if (tag === 'stability') {
} else if (tag.endsWith('_serializer')) {
} else if (tag === 'shortcut_property') {
if (type.kind === 'interface') {
type.shortcutProperty = value
} else {
assert(jsDocs, false, 'Request and Responses cannot have @shortcut_property')
}
} else if (tag === 'variants') {
} else if (tag === 'variant') {
} else if (tag === 'doc_url') {
Expand Down
15 changes: 11 additions & 4 deletions docs/behaviors.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,25 @@ Behaviors should be used via `implements` in the specification.

You can find all the special classes and aliases in in the [modeling guide](./modeling-guide.md).

## AdditionalProperties
## AdditionalProperties & AdditionalProperty

In some places in the specification an object consists of the union of a set of known properties
and a set of runtime injected properties. Meaning that object should theoretically extend Dictionary but expose
a set of known keys and possibly. The object might already be part of an object graph and have a parent class.
This puts it into a bind that needs a client specific solution.
and a set of runtime injected properties. Meaning that object should theoretically extend `Dictionary` but expose
a set of known keys. The object might also be part of an object graph and have a parent class.
This puts it into a bin that needs a client specific solution.
We therefore document the requirement to behave like a dictionary for unknown properties with this interface.

```ts
class IpRangeBucket implements AdditionalProperties<AggregateName, Aggregate> {}
```

There are also many places where we expect only one runtime-defined property, such as in field-related queries. To capture that uniqueness constraint, we can use the `AdditionalProperty` (singular) behavior.

```ts
class GeoBoundingBoxQuery extends QueryBase
implements AdditionalProperty<Field, BoundingBox>
```

## CommonQueryParameters

Implements a set of common query parameters all API's support.
Expand Down
19 changes: 19 additions & 0 deletions docs/modeling-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,25 @@ class AggregationContainer {
avg?: AverageAggregation
...
```

### Shortcut properties

In many places Elasticsearch accepts a property value to be either a complete data structure or a single value, that value being a shortcut for a property in the data structure.

A typical example can be found in queries such as term query: `{"term": {"some_field": {"value": "some_text"}}}` can also be written as `{"term": {"some_field": "some_text"}}`.

This could be modelled as a union of `SomeClass | string`, but this notation doesn't capture the relation between the string variant and the corresponding field (`value` in the above example).

To capture this information and also simplify the spec by avoiding the union, we use the `@shortcut_property` JSDoc tag:

```ts
/** @shortcut_property value */
export class TermQuery extends QueryBase {
value: string | float | boolean
case_insensitive?: boolean
}
```

### Additional information

If needed, you can specify additional information on each type with the approariate JSDoc tag.
Expand Down
Loading