databricks-sdk-go
databricks-sdk-go copied to clipboard
Experimental support for generating Lakeview widgets - `oneOf` and `anyOf`
Changes
- added
constsupport - added
noConstfield 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
constOnlyto facilitatebody = { {{range .Fields | constOnly}}'{{.Name}}': {{template "const" .Entity}},{{end}} } - added
oneOfsupport with constant discriminators - added
anyOfsupport withis_assignablefunctionality 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 essentiallylist[FooOrBar] && FooOrBar = Foo | Bar), but cannot supportlist[Foo] | list[Bar]
cons:
- we don't know JSON-level field names, so we have to convert idiomatic field
names_like_thistonamesLikeThison a per-module basis, if we want to supportanyOfwith 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
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%.
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.