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

Add support for nullable primitive lists #2042

Merged
merged 17 commits into from
Jun 16, 2023
1 change: 1 addition & 0 deletions .generator/src/generator/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def cli(specs, output):
env.filters["format_server"] = openapi.format_server
env.filters["format_value"] = formatter.format_value
env.filters["is_reference"] = formatter.is_reference
env.filters["is_primitive"] = formatter.is_primitive
env.filters["parameter_schema"] = openapi.parameter_schema
env.filters["parameters"] = openapi.parameters
env.filters["form_parameter"] = openapi.form_parameter
Expand Down
11 changes: 11 additions & 0 deletions .generator/src/generator/formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@
}


def is_primitive(schema):
_type = schema.get("type", "object")
return _type in PRIMITIVE_TYPES and "enum" not in schema


def block_comment(comment, prefix="#", first_line=True):
lines = comment.split("\n")
start = "" if first_line else lines[0] + "\n"
Expand Down Expand Up @@ -487,6 +492,8 @@ def format_data_with_schema_list(
if not schema:
return ""

nullable = schema.get("nullable")

if "oneOf" in schema:
parameters = ""
matched = 0
Expand Down Expand Up @@ -571,6 +578,10 @@ def format_data_with_schema_list(
parameters = f"{{\n{parameters}}}"
return parameters

if nullable and is_primitive(list_schema):
name_prefix="datadog.NewNullableList"
return f"*{name_prefix}(&{nested_simple_type_name}{{\n{parameters}}})"

return f"{nested_simple_type_name}{{\n{parameters}}}"


Expand Down
4 changes: 4 additions & 0 deletions .generator/src/generator/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ def type_to_go(schema, alternative_name=None, render_nullable=False, render_new=
# handle nullable arrays
if formatter.simple_type(schema["items"]) and schema["items"].get("nullable"):
name = "*" + name
if schema.get("nullable") and formatter.is_primitive(schema["items"]):
name = formatter.simple_type(schema["items"], render_nullable=render_nullable, render_new=render_new)
if render_nullable:
return f"datadog.{prefix}List[{name}]"
return "[]{}".format(name)
elif type_ == "object":
if "additionalProperties" in schema:
Expand Down
31 changes: 16 additions & 15 deletions .generator/src/generator/templates/model_simple.j2
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func New{{ name }}WithDefaults() *{{ name }} {
{%- set isNullable = spec.nullable %}
{%- set isContainer = spec.type == "array" %}
{%- set isAdditionalPropertiesContainer = spec.type == "object" and spec.get("additionalProperties") and not spec.get("properties") %}
{%- set isPrimitiveContainer = spec.type == "array" and spec["items"]|is_primitive %}
{%- set isAnyType = not dataType.startswith("[]") and not dataType.startswith("map[") %}
{%- if attr in model.get("required", []) %}
// Get{{ propertyName }} returns the {{ propertyName }} field value.
Expand All @@ -111,13 +112,13 @@ func New{{ name }}WithDefaults() *{{ name }} {
// Deprecated
{%- endif %}
func (o *{{ name }}) Get{{ propertyName }}() {{ baseType }} {
if o == nil{%- if isNullable %}{% if not (isContainer or isAdditionalPropertiesContainer) %} || o.{{ propertyName }}.Get() == nil{%- endif %}{%- endif %} {
if o == nil{%- if isNullable %}{% if not ((isContainer and not isPrimitiveContainer) or isAdditionalPropertiesContainer) %} || o.{{ propertyName }}.Get() == nil{%- endif %}{%- endif %} {
var ret {{ baseType }}
return ret
}

{%- if isNullable %}
{%- if isContainer or isAdditionalPropertiesContainer %}
{%- if (isContainer and not isPrimitiveContainer) or isAdditionalPropertiesContainer %}
return o.{{ propertyName }}
{%- else %}
return *o.{{ propertyName }}.Get()
Expand All @@ -136,11 +137,11 @@ func (o *{{ name }}) Get{{ propertyName }}() {{ baseType }} {
// Deprecated
{%- endif %}
func (o *{{ name }}) Get{{ propertyName }}Ok() (*{{ baseType }}, bool) {
if o == nil {%- if isNullable and (isContainer or isAdditionalPropertiesContainer) %}|| o.{{ propertyName }} == nil{%- endif %} {
if o == nil {%- if isNullable and ((isContainer and not isPrimitiveContainer) or isAdditionalPropertiesContainer) %}|| o.{{ propertyName }} == nil{%- endif %} {
return nil, false
}
{%- if isNullable %}
{%- if isContainer or isAdditionalPropertiesContainer %}
{%- if (isContainer and not isPrimitiveContainer) or isAdditionalPropertiesContainer %}
return &o.{{ propertyName }}, true
{%- else %}
return o.{{ propertyName }}.Get(), o.{{ propertyName }}.IsSet()
Expand All @@ -156,7 +157,7 @@ func (o *{{ name }}) Get{{ propertyName }}Ok() (*{{ baseType }}, bool) {
{%- endif %}
func (o *{{ name }}) Set{{ propertyName }}(v {{ baseType }}) {
{%- if isNullable %}
{%- if isContainer or isAdditionalPropertiesContainer %}
{%- if (isContainer and not isPrimitiveContainer) or isAdditionalPropertiesContainer %}
o.{{ propertyName }} = v
{%- else %}
o.{{ propertyName }}.Set(&v)
Expand All @@ -173,12 +174,12 @@ func (o *{{ name }}) Set{{ propertyName }}(v {{ baseType }}) {
// Deprecated
{%- endif %}
func (o *{{ name }}) Get{{ propertyName }}() {{ baseType }} {
if o == nil {% if not isNullable %}|| o.{{ propertyName }} == nil{%- endif %}{%- if isNullable %}{% if not (isContainer or isAdditionalPropertiesContainer) %}|| o.{{ propertyName }}.Get() == nil{%- endif %}{%- endif %} {
if o == nil {% if not isNullable %}|| o.{{ propertyName }} == nil{%- endif %}{%- if isNullable %}{% if not ((isContainer and not isPrimitiveContainer) or isAdditionalPropertiesContainer) %}|| o.{{ propertyName }}.Get() == nil{%- endif %}{%- endif %} {
var ret {{ baseType }}
return ret
}
{%- if isNullable %}
{%- if isContainer or isAdditionalPropertiesContainer %}
{%- if (isContainer and not isPrimitiveContainer) or isAdditionalPropertiesContainer %}
return o.{{ propertyName }}
{%- else %}
return *o.{{ propertyName }}.Get()
Expand All @@ -197,11 +198,11 @@ func (o *{{ name }}) Get{{ propertyName }}() {{ baseType }} {
// Deprecated
{%- endif %}
func (o *{{ name }}) Get{{ propertyName }}Ok() (*{{ baseType }}, bool) {
if o == nil {% if not isNullable %}|| o.{{ propertyName }} == nil{%- endif %}{%- if isNullable %}{%- if isContainer or isAdditionalPropertiesContainer %}|| o.{{ propertyName }} == nil{%- endif %}{%- endif %} {
if o == nil {% if not isNullable %}|| o.{{ propertyName }} == nil{%- endif %}{%- if isNullable %}{%- if (isContainer and not isPrimitiveContainer) or isAdditionalPropertiesContainer %}|| o.{{ propertyName }} == nil{%- endif %}{%- endif %} {
return nil, false
}
{%- if isNullable %}
{%- if isContainer or isAdditionalPropertiesContainer %}
{%- if (isContainer and not isPrimitiveContainer) or isAdditionalPropertiesContainer %}
return &o.{{ propertyName }}, true
{%- else %}
return o.{{ propertyName }}.Get(), o.{{ propertyName }}.IsSet()
Expand All @@ -213,7 +214,7 @@ func (o *{{ name }}) Get{{ propertyName }}Ok() (*{{ baseType }}, bool) {

// Has{{ propertyName }} returns a boolean if a field has been set.
func (o *{{ name }}) Has{{ propertyName }}() bool {
return o != nil && {% if not isNullable %}o.{{ propertyName }} != nil{%- else %}{%- if isContainer or isAdditionalPropertiesContainer %}o.{{ propertyName }} != nil{%- else %}o.{{ propertyName }}.IsSet(){%- endif %}{%- endif %}
return o != nil && {% if not isNullable %}o.{{ propertyName }} != nil{%- else %}{%- if (isContainer and not isPrimitiveContainer) or isAdditionalPropertiesContainer %}o.{{ propertyName }} != nil{%- else %}o.{{ propertyName }}.IsSet(){%- endif %}{%- endif %}
}

// Set{{ propertyName }} gets a reference to the given {{ dataType }} and assigns it to the {{ propertyName }} field.
Expand All @@ -222,7 +223,7 @@ func (o *{{ name }}) Has{{ propertyName }}() bool {
{%- endif %}
func (o *{{ name }}) Set{{ propertyName }}(v {{ baseType }}) {
{%- if isNullable %}
{%- if isContainer or isAdditionalPropertiesContainer %}
{%- if (isContainer and not isPrimitiveContainer) or isAdditionalPropertiesContainer %}
o.{{ propertyName }} = v
{%- else %}
o.{{ propertyName }}.Set(&v)
Expand All @@ -232,7 +233,7 @@ func (o *{{ name }}) Set{{ propertyName }}(v {{ baseType }}) {
{%- endif %}
}
{%- if isNullable %}
{%- if isContainer or isAdditionalPropertiesContainer %}
{%- if (isContainer and not isPrimitiveContainer) or isAdditionalPropertiesContainer %}
{%- else %}
// Set{{ propertyName }}Nil sets the value for {{ propertyName }} to be an explicit nil.
func (o *{{ name }}) Set{{ propertyName }}Nil() {
Expand Down Expand Up @@ -268,16 +269,16 @@ func (o {{ name }}) MarshalJSON() ([]byte, error) {
{%- set isNullable = spec.nullable %}
{%- set isContainer = spec.type == "array" %}
{%- set isAdditionalPropertiesContainer = spec.type == "object" and spec.get("additionalProperties") and not spec.get("properties") %}
{%- set isPrimitiveContainer = spec.type == "array" and spec["items"]|is_primitive %}
{%- set isAnyType = not dataType.startswith("[]") and not dataType.startswith("map[") %}
{#- if argument is nullable, only serialize it if it is set #}
{%- if isNullable %}
{%- if isContainer or isAdditionalPropertiesContainer %}
{#- support for container fields is not ideal at this point because of lack of Nullable* types #}
{%- if (isContainer and not isPrimitiveContainer) or isAdditionalPropertiesContainer %}
if o.{{ propertyName }} != nil {
toSerialize["{{ attr }}"] = o.{{ propertyName }}
}
{%- endif %}
{%- if not (isContainer or isAdditionalPropertiesContainer) %}
{%- if not ((isContainer and not isPrimitiveContainer) or isAdditionalPropertiesContainer) %}
{%- if isRequired %}
toSerialize["{{ attr }}"] = o.{{ propertyName }}.Get()
{%- else %}
Expand Down
44 changes: 44 additions & 0 deletions .generator/src/generator/templates/utils.j2
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,50 @@ func (v *NullableTime) UnmarshalJSON(src []byte) error {
return json.Unmarshal(src, &v.value)
}

// NullableList struct to hold nullable list value.
type NullableList[T any] struct {
value *[]T
isSet bool
}

// Get returns the value associated with the nullable list.
func (v NullableList[T]) Get() *[]T {
return v.value
}

// Set sets the value associated with the nullable list.
func (v *NullableList[T]) Set(val *[]T) {
v.value = val
v.isSet = true
}

// IsSet returns true if the value has been set.
func (v NullableList[T]) IsSet() bool {
return v.isSet
}

// Unset resets fields of the nullable list.
func (v *NullableList[T]) Unset() {
v.value = nil
v.isSet = false
}

// NewNullableList instantiates a new nullable list.
func NewNullableList[T any](val *[]T) *NullableList[T] {
return &NullableList[T]{value: val, isSet: true}
}

// MarshalJSON serializes the associated value.
func (v NullableList[T]) MarshalJSON() ([]byte, error) {
return json.Marshal(v.value)
}

// UnmarshalJSON deserializes to the associated value.
func (v *NullableList[T]) UnmarshalJSON(src []byte) error {
v.isSet = true
return json.Unmarshal(src, &v.value)
}

// DeleteKeys helper method to delete keys from a map
func DeleteKeys[V any](obj map[string]V, keysToDelete *[]string) {
for _, s := range *keysToDelete {
Expand Down
44 changes: 44 additions & 0 deletions api/datadog/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,50 @@ func (v *NullableTime) UnmarshalJSON(src []byte) error {
return json.Unmarshal(src, &v.value)
}

// NullableList struct to hold nullable list value.
type NullableList[T any] struct {
value *[]T
isSet bool
}

// Get returns the value associated with the nullable list.
func (v NullableList[T]) Get() *[]T {
return v.value
}

// Set sets the value associated with the nullable list.
func (v *NullableList[T]) Set(val *[]T) {
v.value = val
v.isSet = true
}

// IsSet returns true if the value has been set.
func (v NullableList[T]) IsSet() bool {
return v.isSet
}

// Unset resets fields of the nullable list.
func (v *NullableList[T]) Unset() {
v.value = nil
v.isSet = false
}

// NewNullableList instantiates a new nullable list.
func NewNullableList[T any](val *[]T) *NullableList[T] {
return &NullableList[T]{value: val, isSet: true}
}

// MarshalJSON serializes the associated value.
func (v NullableList[T]) MarshalJSON() ([]byte, error) {
return json.Marshal(v.value)
}

// UnmarshalJSON deserializes to the associated value.
func (v *NullableList[T]) UnmarshalJSON(src []byte) error {
v.isSet = true
return json.Unmarshal(src, &v.value)
}

// DeleteKeys helper method to delete keys from a map
func DeleteKeys[V any](obj map[string]V, keysToDelete *[]string) {
for _, s := range *keysToDelete {
Expand Down
Loading