Skip to content

Commit 2175946

Browse files
authored
feat: Add WithNullableFieldTransformer to transformers.TransformWithStruct options (#2084)
<!-- Explain what problem this PR addresses --> Fixes cloudquery/cloudquery#20286 Add `transformers.WithNullableFieldTransformer(func ...)` to allow the SDK user to have custom rules to decide for a field nullability. This is especially useful when the user defines its struct with some pointers and some regular value types: we can have the that set `nil` for pointers, non `nil` for non-pointers. ---
1 parent fc27b14 commit 2175946

File tree

4 files changed

+55
-0
lines changed

4 files changed

+55
-0
lines changed

transformers/nullable_field.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package transformers
2+
3+
import "reflect"
4+
5+
type NullableFieldTransformer func(field reflect.StructField) bool
6+
7+
func DefaultNullableFieldTransformer(_ reflect.StructField) bool {
8+
return true
9+
}
10+
11+
var _ NullableFieldTransformer = DefaultNullableFieldTransformer

transformers/options.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ func WithIgnoreInTestsTransformer(transformer IgnoreInTestsTransformer) StructTr
6363
}
6464
}
6565

66+
// WithNullableFieldTransformer overrides how column NotNull will be determined.
67+
// DefaultNullableFieldTransformer is used as the default.
68+
func WithNullableFieldTransformer(transformer NullableFieldTransformer) StructTransformerOption {
69+
return func(t *structTransformer) {
70+
t.nullableFieldTransformer = transformer
71+
}
72+
}
73+
6674
// WithPrimaryKeys allows to specify what struct fields should be used as primary keys
6775
func WithPrimaryKeys(fields ...string) StructTransformerOption {
6876
return func(t *structTransformer) {

transformers/struct.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type structTransformer struct {
2323
typeTransformer TypeTransformer
2424
resolverTransformer ResolverTransformer
2525
ignoreInTestsTransformer IgnoreInTestsTransformer
26+
nullableFieldTransformer NullableFieldTransformer
2627
unwrapAllEmbeddedStructFields bool
2728
structFieldsToUnwrap []string
2829
pkFields []string
@@ -161,6 +162,7 @@ func (t *structTransformer) addColumnFromField(field reflect.StructField, parent
161162
Type: columnType,
162163
Resolver: resolver,
163164
IgnoreInTests: t.ignoreInTestsTransformer(field),
165+
NotNull: !t.nullableFieldTransformer(field),
164166
}
165167

166168
// Enrich JSON column with detailed schema
@@ -199,6 +201,7 @@ func TransformWithStruct(st any, opts ...StructTransformerOption) schema.Transfo
199201
typeTransformer: DefaultTypeTransformer,
200202
resolverTransformer: DefaultResolverTransformer,
201203
ignoreInTestsTransformer: DefaultIgnoreInTestsTransformer,
204+
nullableFieldTransformer: DefaultNullableFieldTransformer,
202205
jsonSchemaNameTransformer: DefaultJSONColumnSchemaNameTransformer,
203206
maxJSONTypeSchemaDepth: DefaultMaxJSONTypeSchemaDepth,
204207
}

transformers/struct_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ type (
8282
IntCol int `json:"int_col"`
8383
Properties any
8484
}
85+
86+
testNullableField struct {
87+
RegularString string `json:"regular_string"`
88+
NullableString *string `json:"nullable_string"`
89+
}
8590
)
8691

8792
var (
@@ -301,6 +306,22 @@ var (
301306
},
302307
},
303308
}
309+
310+
expectedTestTableStructNonNullableFields = schema.Table{
311+
Name: "test_struct_with_non_nullable_fields",
312+
Columns: schema.ColumnList{
313+
{
314+
Name: "regular_string",
315+
Type: arrow.BinaryTypes.String,
316+
NotNull: true,
317+
},
318+
{
319+
Name: "nullable_string",
320+
Type: arrow.BinaryTypes.String,
321+
NotNull: false,
322+
},
323+
},
324+
}
304325
)
305326

306327
func TestTableFromGoStruct(t *testing.T) {
@@ -443,6 +464,18 @@ func TestTableFromGoStruct(t *testing.T) {
443464
},
444465
want: expectedTestTableStructWithCustomAny,
445466
},
467+
{
468+
name: "Should be able to override any nullability for a field",
469+
args: args{
470+
testStruct: testNullableField{},
471+
options: []StructTransformerOption{
472+
WithNullableFieldTransformer(func(f reflect.StructField) bool {
473+
return f.Type.Kind() == reflect.Pointer
474+
}),
475+
},
476+
},
477+
want: expectedTestTableStructNonNullableFields,
478+
},
446479
}
447480

448481
for _, tt := range tests {

0 commit comments

Comments
 (0)