databricks-sdk-go icon indicating copy to clipboard operation
databricks-sdk-go copied to clipboard

Experimental support for generating Lakeview widgets - `oneOf` and `anyOf`

Open nfx opened this issue 1 year ago • 1 comments

Changes

  • added const support
  • addednoConst field slice filters to facilitate {{- range .NonRequiredFields | alphanumOnly | noConst}} - most likely we don't need it, as we should better manipulate field maps in different passes
  • added constOnly to facilitate body = { {{range .Fields | constOnly}}'{{.Name}}': {{template "const" .Entity}},{{end}} }
  • added oneOf support with constant discriminators
  • added anyOf support with is_assignable functionality delegated to a target language.

Reference Python implementation of a supertype with constant discriminator resolution

Subtype name and version are decoupled from the actual type deserialization

class WidgetSpec(abc.ABC):
    @abc.abstractmethod
    def as_dict(self) -> Json:
        raise NotImplementedError

    @classmethod
    def from_dict(cls, d: Json) -> WidgetSpec:
        if d["version"] == 1 and d["widgetType"] == "details":
            return DetailsV1Spec.from_dict(d)
        elif d["version"] == 1 and d["widgetType"] == "table":
            return TableV1Spec.from_dict(d)
        #... 
        else:
            raise KeyError(f'unknown: version={d["version"]} widgetType={d["widgetType"]}')

Example Python implementation with constant discriminators

Type serialization silently encodes type/version metadata and ignores that on read

@dataclass
class CounterSpec(WidgetSpec):
    encodings: CounterEncodingMap
    format: FormatConfig | None = None
    frame: WidgetFrameSpec | None = None

    def as_dict(self) -> Json:
        body: Json = {
            "version": 2,
            "widgetType": "counter",
        }
        if self.encodings:
            body["encodings"] = self.encodings.as_dict()
        if self.format:
            body["format"] = self.format.as_dict()
        if self.frame:
            body["frame"] = self.frame.as_dict()
        return body

    @classmethod
    def from_dict(cls, d: Json) -> CounterSpec:
        return cls(
            encodings=_from_dict(d, "encodings", CounterEncodingMap),
            format=_from_dict(d, "format", FormatConfig),
            frame=_from_dict(d, "frame", WidgetFrameSpec),
        )

Loose supertype implementation in Python

pros:

  • we can emulate TypeScript's compile-time interface-on-read during runtime
  • we can support list[Foo | Bar] (which is essentially list[FooOrBar] && FooOrBar = Foo | Bar), but cannot support list[Foo] | list[Bar]

cons:

  • we don't know JSON-level field names, so we have to convert idiomatic field names_like_this to namesLikeThis on a per-module basis, if we want to support anyOf with loose typing
class ControlEncoding(abc.ABC):
    @abc.abstractmethod
    def as_dict(self) -> Json:
        raise NotImplementedError

    @classmethod
    def from_dict(cls, d: Json) -> ControlEncoding:
        reasons = []
        yes, why_not = _is_assignable(ControlFieldEncoding, d, [], _snake_to_camel)
        if yes:
            return ControlFieldEncoding.from_dict(d)
        if why_not:
            reasons.append(why_not)
        yes, why_not = _is_assignable(ParameterEncoding, d, [], _snake_to_camel)
        if yes:
            return ParameterEncoding.from_dict(d)
        if why_not:
            reasons.append(why_not)
        raise KeyError(" and ".join(reasons))

Tests

  • manual tests only

nfx avatar Jan 18 '24 10:01 nfx

Codecov Report

Attention: 164 lines in your changes are missing coverage. Please review.

Comparison is base (aad9abf) 18.27% compared to head (d8bdf9b) 18.13%.

Files Patch % Lines
openapi/code/polymorphism.go 13.92% 132 Missing and 4 partials :warning:
openapi/code/tmpl_util_funcs.go 0.00% 10 Missing :warning:
openapi/code/package.go 42.85% 6 Missing and 2 partials :warning:
openapi/model.go 0.00% 6 Missing :warning:
openapi/code/load.go 60.00% 2 Missing and 2 partials :warning:
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #774      +/-   ##
==========================================
- Coverage   18.27%   18.13%   -0.14%     
==========================================
  Files         110      112       +2     
  Lines       14834    15113     +279     
==========================================
+ Hits         2711     2741      +30     
- Misses      11901    12142     +241     
- Partials      222      230       +8     

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

codecov-commenter avatar Jan 19 '24 15:01 codecov-commenter