forcedotcom / go-soql

Golang tag library to generate SOQL queries
BSD 3-Clause "New" or "Revised" License
51 stars 12 forks source link

Add support for orderby clause #3

Closed atulkc closed 4 years ago

atulkc commented 4 years ago

Library should support ORDER BY clause. User should be able to annotate []string member of struct with orderBy tag and indicate if the order is ASC or DESC. The values in the []string should be the names of the field of the struct that is tagged as selectClause. This will enable developers to take []string as parameter to their method where the users of their library can specify the name of the fields of the struct that is being returned to them on which they desire ordering. Below given is example of how this should work:

type TestSoqlStruct struct {
    SelectClause NonNestedStruct   `soql:"selectClause,tableName=SM_SomeObject__c"`
    WhereClause  TestQueryCriteria `soql:"whereClause"`
    OrderByAsc   []string          `soql:"orderByClause,order=ASC"`
    OrderByDesc  []string          `soql:"orderByClause,order=DESC"`
}
type TestQueryCriteria struct {
    IncludeNamePattern          []string `soql:"likeOperator,fieldName=Name__c"`
    Roles                       []string `soql:"inOperator,fieldName=Role__c"`
}
type NonNestedStruct struct {
    Name          string `soql:"selectColumn,fieldName=Name__c"`
    SomeValue     string `soql:"selectColumn,fieldName=SomeValue__c"`
}

To use above structs to create SOQL query

soqlStruct := TestSoqlStruct{
    WhereClause: TestQueryCriteria {
        IncludeNamePattern: []string{"foo", "bar"},
        Roles: []string{"admin", "user"},
    },
   OrderByAsc: []string{"Name"},
   OrderByDesc: []string{"SomeValue"},
}
soqlQuery, err := Marshal(soqlStruct)
if err != nil {
    fmt.Printf("Error in marshaling: %s\n", err.Error())
}
fmt.Println(soqlQuery)

Above struct will result in following SOQL query:

SELECT Name,SomeValue__c FROM SM_SomeObject__C WHERE (Name__c LIKE '%foo%' OR Name__c LIKE '%bar%') AND Role__c IN ('admin','user') ORDER BY Name__c ASC, SomeValue___c DESC
kchoy-sfdc commented 4 years ago

The above design would not support the case of mixing ASC and DESC order, e.g. SELECT col1, col2, col3 FROM table1 ORDER BY col1 ASC, col2 DESC, col3 ASC, since we are keeping the order by columns as two separate slices.

I suggest creating a struct that contains the name of the column and its ordering, and allow users to provide a slice of this struct to construct the ORDER BY clause:

type Order struct {
    Field string
    IsDesc bool
}

And the TestSoqlStruct would look like:

type TestSoqlStruct struct {
    SelectClause  NonNestedStruct   `soql:"selectClause,tableName=SM_SomeObject__c"`
    WhereClause   TestQueryCriteria `soql:"whereClause"`
    OrderByClause []Order           `soql:"orderByClause"`
}

To generate the ORDER BY clause ORDER BY Name__c ASC, SomeValue___c DESC, SomeValue2__c ASC, we would create the following slice and set it to TestSoqlStruct.OrderByClause:

ordering := []Order{
    Order{"Name", false},
    Order{"SomeValue", true},
    Order{"SomeValue2", false},
}
atulkc commented 4 years ago

@kchoy-sfdc good catch about limitation of proposed solution. Thanks for suggesting a new solution. I agree with your approach. Lets use your suggestion in building this feature.