diff --git a/marshaller.go b/marshaller.go index fc7d49b..19582bb 100644 --- a/marshaller.go +++ b/marshaller.go @@ -85,6 +85,8 @@ const ( TableName = "tableName" // SelectColumn is the tag to be used for selecting a column in select clause SelectColumn = "selectColumn" + // SelectSingle is the tag to be used for selecting a column in select clause without breaking a struct + SelectOpaque = "selectOpaque" // SelectChild is the tag to be used when selecting from child tables SelectChild = "selectChild" // FieldName is the parameter to be used to specify the name of the field in underlying SOQL object @@ -511,7 +513,8 @@ func mapSelectColumns(mappings map[string]string, parent string, gusParent strin continue } // skip all fields that are not tagged as selectColumn - if getClauseKey(tag) != SelectColumn { + clauseKey := getClauseKey(tag) + if clauseKey != SelectColumn && clauseKey != SelectOpaque { continue } @@ -947,9 +950,13 @@ func MarshalSelectClause(v interface{}, relationShipName string) (string, error) } clauseKey := getClauseKey(clauseTag) isChildRelation := false + breakStructs := true switch clauseKey { case SelectColumn: isChildRelation = false + case SelectOpaque: + isChildRelation = false + breakStructs = false case SelectChild: isChildRelation = true default: @@ -966,7 +973,7 @@ func MarshalSelectClause(v interface{}, relationShipName string) (string, error) } buff.WriteString(subStr) } else { - if field.Type.Kind() == reflect.Struct { + if field.Type.Kind() == reflect.Struct && breakStructs { v := reflect.New(field.Type) subStr, err := MarshalSelectClause(v.Elem().Interface(), prefix+fieldName) if err != nil { diff --git a/marshaller_test.go b/marshaller_test.go index 181d886..4fdddd3 100644 --- a/marshaller_test.go +++ b/marshaller_test.go @@ -1026,6 +1026,17 @@ var _ = Describe("Marshaller", func() { Expect(clause).To(Equal("Major_OS_Version__c DESC,Num_of_CPU_Cores__c ASC,Physical_CPU_Count__c DESC,Last_Restart__c ASC")) }) }) + + Context("when an Order slice referring to a SelectOpaque field is passed", func() { + It("returns a valid order clause", func() { + col1 := Order{Field: "OpaqueField", IsDesc: true} + clause, err := MarshalOrderByClause([]Order{col1}, struct { + OpaqueField OpaqueStructSoql `soql:"selectOpaque,fieldName=Role__c"` + }{}) + Expect(err).ToNot(HaveOccurred()) + Expect(clause).To(Equal("Role__c DESC")) + }) + }) }) Context("when invalid order by is passed as argument", func() { @@ -1096,6 +1107,22 @@ var _ = Describe("Marshaller", func() { Expect(str).To(Equal("Id,Name__c,NonNestedStruct__r.Name,NonNestedStruct__r.SomeValue__c")) }) }) + + Context("when nested struct with soql fields is selected opaquely", func() { + It("returns properly resolved list of field names without breaking up dontbreak", func() { + str, err := MarshalSelectClause(NestedStructWithOpaqueSoql{}, "") + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(Equal("Id,Name__c,DontBreak__c")) + }) + }) + + Context("when nested struct with no soql fields is selected opaquely", func() { + It("returns properly resolved list of field names without breaking up nobreak", func() { + str, err := MarshalSelectClause(NestedStructWithOpaqueNonSoql{}, "") + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(Equal("Id,Name__c,DontBreak__c")) + }) + }) }) Context("when relationship name is passed", func() { diff --git a/soql_suite_test.go b/soql_suite_test.go index c505c64..a074ec7 100644 --- a/soql_suite_test.go +++ b/soql_suite_test.go @@ -58,6 +58,26 @@ type NestedStruct struct { NonNestedStruct NonNestedStruct `soql:"selectColumn,fieldName=NonNestedStruct__r"` } +type OpaqueStructSoql struct { + Role string `soql:"selectColumn,fieldName=Role"` +} + +type OpaqueStructNonSoql struct { + Role string +} + +type NestedStructWithOpaqueSoql struct { + ID string `soql:"selectColumn,fieldName=Id"` + Name string `soql:"selectColumn,fieldName=Name__c"` + DontBreak OpaqueStructSoql `soql:"selectOpaque,fieldName=DontBreak__c"` +} + +type NestedStructWithOpaqueNonSoql struct { + ID string `soql:"selectColumn,fieldName=Id"` + Name string `soql:"selectColumn,fieldName=Name__c"` + DontBreak OpaqueStructNonSoql `soql:"selectOpaque,fieldName=DontBreak__c"` +} + type TestChildStruct struct { SelectClause ChildStruct `soql:"selectClause,tableName=SM_Application_Versions__c"` WhereClause ChildQueryCriteria `soql:"whereClause"`