profile
viewpoint
Atul Kshirsagar atulkc San Ramon, CA, US

forcedotcom/go-soql 8

Golang tag library to generate SOQL queries

atulkc/ethereum-release 1

BOSH release for ethereum

atulkc/candiedyaml 0

YAML for Go

atulkc/cli 0

A CLI for Cloud Foundry written in Go

atulkc/fabric 0

THIS IS A READ-ONLY historic repository. Current development is at https://gerrit.hyperledger.org/r/#/admin/projects/fabric . pull requests not accepted

atulkc/karaf 0

Mirror of Apache Karaf

atulkc/routing-release 0

This is BOSH release for cloud foundry routers

atulkc/ssh 0

Easy SSH servers in Golang

markstgodard/treadmill 0

The lil' gorouter stress test

issue openedforcedotcom/go-soql

Add support for avg/sum functions

As part of supporting aggregate functions add support for following functions:

AVG()
SUM()

Add avg and sum tag that can be used in selectClause structs as follows:

type TestSoqlStruct struct {
	SelectClause NestedStruct      `soql:"selectClause,tableName= Opportunity"`
	GroupBy        []string                 `soql:"groupByClause"`
}

type NestedStruct struct {
        CampaignId  string `soql:"selectColumn,fieldName= CampaignId"`
	Average         int `soql:"avg,fieldName= Amount"`
}

soqlStruct := TestSoqlStruct{
   GroupBy: []string{"CampaignId"},
}
soqlQuery, err := Marshal(soqlStruct)
if err != nil {
    fmt.Printf("Error in marshaling: %s\n", err.Error())
}
fmt.Println(soqlQuery)

This should result in SOQL as follows

SELECT CampaignId, AVG(Amount) FROM Opportunity GROUP BY CampaignId

Note that if fieldName is not specified then return ErrInvalidTag.

Same should apply for sum tag as well.

Allow avg and sum to be used only for supported primitive data types

created time in a month

issue openedforcedotcom/go-soql

Add support min/max functions

As part of supporting aggregate functions add support for following functions:

MIN()
MAX()

Add min and max tag that can be used in selectClause structs as follows:

type TestSoqlStruct struct {
	SelectClause NestedStruct      `soql:"selectClause,tableName= Contact"`
	GroupBy        []string                 `soql:"groupByClause"`
}
type TestQueryCriteria struct {
	IncludeNamePattern          []string `soql:"likeOperator,fieldName=Name"`	
}

type NestedStruct struct {
	Count            int `soql:"min,fieldName= CreatedDate"`
}

This should result in SOQL as follows

SELECT MIN(CreatedDate) FROM Contact WHERE Name LIKE '%a%'

Note that if fieldName is not specified then return ErrInvalidTag.

Same should apply for max tag as well.

Allow min and max to be used only for supported primitive data types

created time in a month

issue openedforcedotcom/go-soql

Add support for count function in SOQL

As part of supporting aggregate functions add support for following functions:

COUNT()
COUNT_DISTINCT()

Add count and countDistinct tag that can be used in selectClause structs as follows:

type TestSoqlStruct struct {
	SelectClause NestedStruct      `soql:"selectClause,tableName=Account"`
	WhereClause  TestQueryCriteria `soql:"whereClause"`
}
type TestQueryCriteria struct {
	IncludeNamePattern          []string `soql:"likeOperator,fieldName=Name"`	
}

type NestedStruct struct {
	Count            int `soql:"count"`
}

This should result in SOQL as follows

SELECT COUNT() FROM Account WHERE Name LIKE '%a%'

Note that if fieldName is not specified then just COUNT() should be used. If fieldName is specified then that should be used.

type TestSoqlStruct struct {
	SelectClause NestedStruct      `soql:"selectClause,tableName=Account"`
	WhereClause  TestQueryCriteria `soql:"whereClause"`
}
type TestQueryCriteria struct {
	IncludeNamePattern          []string `soql:"likeOperator,fieldName=Name"`	
}

type NestedStruct struct {
	Count            int `soql:"count,fieldName=Id"`
}
SELECT COUNT(Id) FROM Account WHERE Name LIKE '%a%'

Same should apply for countDistinct tag as well.

Note that if count or countDistinct is used without fieldName then there cannot be any other field in select clause as described here. If groupBy clause is used only then allow selectClause struct to have other fields. In case of error return ErrInvalidCountTag error.

Allow count and countDistinct to be used only for supported primitive data types

created time in a month

issue openedforcedotcom/go-soql

Add support for groupBy clause

Library should support GROUP BY clause. User should be able to annotate []string member of struct with groupBy tag. 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 grouping. Below given is example of how this should work:

type TestSoqlStruct struct {
	SelectClause NonNestedStruct   `soql:"selectClause,tableName=SM_SomeObject__c"`
	WhereClause  TestQueryCriteria `soql:"whereClause"`
	GroupBy   []string                         `soql:"groupByClause"`
}
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"},
    },
   GroupBy: []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') GROUP BY SomeValue___c 

created time in a month

push eventforcedotcom/go-soql

dmaykov

commit sha b3fbefb845e35e3242ec5792a8f8607a2522ffb8

Add support for time.Time pointer * Adding support for *time.Time in WhereClause in case it's optional. * Test case for nil *time.Time

view details

push time in a month

Pull request review commentforcedotcom/go-soql

Adding support for *time.Time in WhereClause in case it's optional.

 type QueryCriteriaWithDateTimeType struct { 	CreatedDate time.Time `soql:"equalsOperator,fieldName=CreatedDate"` } +type QueryCriteriaWithPtrDateTimeType struct {+	CreatedDate *time.Time `soql:"equalsOperator,fieldName=CreatedDate"`

May be just add another time field here and the existing testcase will cover both nil and not nil cases.

dmaykov

comment created time in a month

Pull request review commentforcedotcom/go-soql

Adding support for *time.Time in WhereClause in case it's optional.

 var _ = Describe("Marshaller", func() { 			}) 		}) +		Context("when all clauses are pointers to date time data types", func() {

It will be good to add a testcase where timestamp pointer is nil and verify that it is not included in the where clause.

dmaykov

comment created time in a month

push eventforcedotcom/go-soql

dmaykov

commit sha 638ca0f2ee8d1b3b0c3ff13ec8e72df6d730f050

Allow subqueries to be pointers * Allowing pointers with "subquery" tag in order to support optional conditions in WhereClause. * Handling nil pointer and adding test cases * Improve readability

view details

push time in a month

PR merged forcedotcom/go-soql

Allowing pointers with "subquery" tag (revised) cla:signed

Allowing pointers with "subquery" tag in order to support optional subqueries in WhereClause. It will make behavior consistent with other conditions as they are allowed to be null.

+41 -1

0 comment

3 changed files

dmaykov

pr closed time in a month

push eventforcedotcom/go-soql

Tim Margheim

commit sha 8cfa0f5833172b55f74b71e0a735627fd24188f4

Support for advanced WHERE clause * Add support for joining conditions using `OR` or `AND` * Add support for grouped conditions

view details

push time in 2 months

PR merged forcedotcom/go-soql

Build out subfilter and OR logical operator support cla:signed

Resolves #13 and #14

+378 -20

4 comments

4 changed files

t-margheim

pr closed time in 2 months

issue closedforcedotcom/go-soql

Marshal SOQL queries with subfilters in the WHERE clause

Currently, I don't believe it's possible to generate a query like this:

SELECT Name,Email,Phone 
FROM Contact
WHERE Title = 'Purchasing Manager'
    OR (Department = 'Accounting' AND Title LIKE '%Manager%')
    AND (
        (Email != null AND HasOptedOutOfEmail = false) 
        OR (Phone != null AND DoNotCall = false)
    )

I have a project where I'd like to use this, so I've been experimenting with ways of doing subfilters. I think something like this would make sense:

type contact struct {
	Name  string `soql:"selectColumn,fieldName=Name" json:"Name"`
	Email string `soql:"selectColumn,fieldName=Email" json:"Email"`
	Phone string `soql:"selectColumn,fieldName=Phone" json:"Phone"`
}

type soqlQuery struct {
	SelectClause contact       `soql:"selectClause,tableName=Contact"`
	WhereClause  queryCriteria `soql:"whereClause"`
}

type queryCriteria struct {
	Position    positionCriteria    `soql:"subquery,joiner=OR"`
	Contactable contactableCriteria `soql:"subquery,joiner=OR"`
}

type positionCriteria struct {
	Title             string              `soql:"equalsOperator,fieldName=Title"`
	DepartmentManager deptManagerCriteria `soql:"subquery"`
}

type deptManagerCriteria struct {
	Department string   `soql:"equalsOperator,fieldName=Department"`
	Title      []string `soql:"likeOperator,fieldName=Title"`
}

type contactableCriteria struct {
	EmailOK emailCheck `soql:"subquery,joiner=and"`
	PhoneOK phoneCheck `soql:"subquery,joiner=and"`
}

type emailCheck struct {
	Email         bool `soql:"nullOperator,fieldName=Email"`
	EmailOptedOut bool `soql:"equalsOperator,fieldName=HasOptedOutOfEmail"`
}

type phoneCheck struct {
	Phone     bool `soql:"nullOperator,fieldName=Phone"`
	DoNotCall bool `soql:"equalsOperator,fieldName=DoNotCall"`
}

// this would generate the soql query
soql.Marshal(soqlQuery{
    WhereClause: queryCriteria{
        Position: positionCriteria{
            Title: "Purchasing Manager",
            DepartmentManager: deptManagerCriteria{
                Department: "Accounting",
                Title:      []string{"Manager"},
            },
        },
        Contactable: contactableCriteria{
            EmailOK: emailCheck{
                Email:         false,
                EmailOptedOut: false,
            },
            PhoneOK: phoneCheck{
                Phone:     false,
                DoNotCall: false,
            },
        },
    },
})

closed time in 2 months

t-margheim

issue closedforcedotcom/go-soql

Marshal SOQL queries with OR operators between different columns

Marshal SOQL queries with OR operators between different columns. For example, I don't believe this query is currently marshal-able:

SELECT Name,Email,Phone
FROM Contact
WHERE Title = 'Purchasing Manager' OR Department = 'Accounting'

I've been playing with an implementation that I think might work and is in keeping with the current patterns: adding an optional clause tag called joiner for whereClause. If not set, the marshal function uses AND to join (to maintain current functionality). If it's set to OR (case insensitive), then it will separate the clauses with OR.

type contact struct {
	Name  string `soql:"selectColumn,fieldName=Name" json:"Name"`
	Email string `soql:"selectColumn,fieldName=Email" json:"Email"`
	Phone string `soql:"selectColumn,fieldName=Phone" json:"Phone"`
}

type orSOQLQuery struct {
	SelectClause contact                `soql:"selectClause,tableName=Contact"`
	WhereClause  positionOrDeptCriteria `soql:"whereClause,joiner=OR"`
}

type positionOrDeptCriteria struct {
	Title      string `soql:"equalsOperator,fieldName=Title"`
	Department string `soql:"equalsOperator,fieldName=Department"`
}

// this would generate the soql query
soql.Marshal(orSOQLQuery{
    WhereClause: positionOrDeptCriteria{
        Title:      "Purchasing Manager",
        Department: "Accounting",
    },
})

closed time in 2 months

t-margheim

Pull request review commentforcedotcom/go-soql

Build out subfilter and OR logical operator support

 func marshalWhereClause(v interface{}, tableName string) (string, error) { // This will print whereClause as: // (Host_Name__c LIKE '%-db%' OR Host_Name__c LIKE '%-dbmgmt%') AND Role__r.Name IN ('db','dbmgmt') AND ((NOT Host_Name__c LIKE '%-core%') AND (NOT Host_Name__c LIKE '%-drp%')) AND Tech_Asset__r.Asset_Type_Asset_Type__c = 'SERVER' AND Last_Discovered_Date__c != null AND Num_of_CPU_Cores__c > 16 func MarshalWhereClause(v interface{}) (string, error) {-	return marshalWhereClause(v, "")+	return marshalWhereClause(v, "", andCondition) }  func getClauseKey(clauseTag string) string { 	tagItems := strings.Split(clauseTag, ",") 	return tagItems[0] } +func getJoiner(clauseTag string) (string, error) {+	tag := getTagValue(clauseTag, Joiner, "")+	switch strings.ToLower(tag) {+	case "or":+		return orCondition, nil+	case "and", "":+		return andCondition, nil+	default:

👍

t-margheim

comment created time in 2 months

Pull request review commentforcedotcom/go-soql

Build out subfilter and OR logical operator support

 type NonNestedStruct struct {  1. `selectClause`: This tag is used on the struct which should be considered for generating part of SOQL query that contains columns/fields that should be selected. It should be used only on `struct` type. If used on types other than `struct` then `ErrInvalidTag` error will be returned. This tag is associated with `tableName` parameter. It specifies the name of the table (Salesforce object) from which the columns should be selected. If not specified name of the field is used as table name (Salesforce object). In the snippet above `SelectClause` member of `TestSoqlStruct` is tagged with `selectClause` to indicate that members in `NonNestedStruct` should be considered as fields to be selected from Salesforce object `SM_SomeObject__c`. -1. `whereClause`: This tag is used on the struct which encapsulates the query criteria for SOQL query. There are no parameters for this tag. In the snippet above `WhereClause` member of `TestSoqlStruct` is tagged with `whereClause` to indicate that members in `TestQueryCriteria` should be considered for generating `WHERE` clause in SOQL query. If there are more than one field in `TestQueryCriteria` struct then they will be combined using `AND` logical operator.+1. `whereClause`: This tag is used on the struct which encapsulates the query criteria for SOQL query. There is an optional parameter `joiner` for this tag. In the snippet above `WhereClause` member of `TestSoqlStruct` is tagged with `whereClause` to indicate that members in `TestQueryCriteria` should be considered for generating `WHERE` clause in SOQL query. If there are more than one field in `TestQueryCriteria` struct then they will be combined using `AND` logical operator. If the `joiner` parameter is set to `or`, then the fields will be combined using `OR` logical operator.  Any other value including no value will use the `AND` logical operator. The `joiner` parameter is only supported when using `Marshal`; when calling `MarshalWhereClause`, the fields will always be combined with the `AND` logical operator.

Just need to fix the README to indicate that any other value than AND and OR will result in ErrInvalidTag.

t-margheim

comment created time in 2 months

issue commentforcedotcom/go-soql

Marshal SOQL queries with OR operators between different columns

Thanks @t-margheim for submitting the issue and corresponding PR. I think this is a great addition to this library.

t-margheim

comment created time in 2 months

issue commentforcedotcom/go-soql

Marshal SOQL queries with subfilters in the WHERE clause

Thanks @t-margheim for submitting the issue and corresponding PR

t-margheim

comment created time in 2 months

pull request commentforcedotcom/go-soql

Build out subfilter and OR logical operator support

Resolves #13 and #14

t-margheim

comment created time in 2 months

Pull request review commentforcedotcom/go-soql

Build out subfilter and OR logical operator support

 var _ = Describe("Marshaller", func() { 				Expect(actualQuery).To(Equal(expectedQuery)) 			}) 		})++		Context("when a struct with where clause with joiner=OR passed", func() {+			BeforeEach(func() {+				soqlStruct = orSOQLQuery{+					WhereClause: positionOrDeptCriteria{+						Title:      "Purchasing Manager",+						Department: "Accounting",+					},+				}+				expectedQuery = "SELECT Name,Email,Phone FROM Contact WHERE Title = 'Purchasing Manager' OR Department = 'Accounting'"+			})++			It("returns properly constructed soql query", func() {+				Expect(err).ToNot(HaveOccurred())+				Expect(actualQuery).To(Equal(expectedQuery))+			})+		})++		Context("when a struct with where clause with joiner=or passed", func() {+			BeforeEach(func() {+				soqlStruct = orLowerSOQLQuery{+					WhereClause: positionOrDeptCriteria{+						Title:      "Purchasing Manager",+						Department: "Accounting",+					},+				}+				expectedQuery = "SELECT Name,Email,Phone FROM Contact WHERE Title = 'Purchasing Manager' OR Department = 'Accounting'"+			})++			It("returns properly constructed soql query", func() {+				Expect(err).ToNot(HaveOccurred())+				Expect(actualQuery).To(Equal(expectedQuery))+			})+		})++		Context("when a struct with where clause with joiner=AND passed", func() {+			BeforeEach(func() {+				soqlStruct = andSOQLQuery{+					WhereClause: positionOrDeptCriteria{+						Title:      "Purchasing Manager",+						Department: "Accounting",+					},+				}+				expectedQuery = "SELECT Name,Email,Phone FROM Contact WHERE Title = 'Purchasing Manager' AND Department = 'Accounting'"+			})++			It("returns properly constructed soql query", func() {+				Expect(err).ToNot(HaveOccurred())+				Expect(actualQuery).To(Equal(expectedQuery))+			})+		})++		Context("when a struct with where clause with joiner=ELSE (an invalid value) passed", func() {+			BeforeEach(func() {+				soqlStruct = invalidJoinerSOQLQuery{+					WhereClause: positionOrDeptCriteria{+						Title:      "Purchasing Manager",+						Department: "Accounting",+					},+				}+				expectedQuery = "SELECT Name,Email,Phone FROM Contact WHERE Title = 'Purchasing Manager' AND Department = 'Accounting'"+			})++			It("returns properly constructed soql query", func() {+				Expect(err).ToNot(HaveOccurred())

I think we should return ErrInvalidTag in this case. If value of joiner is anything other than or or and (case insensitive) then we should throw an error. It will prevent surprises for the user.

t-margheim

comment created time in 2 months

Pull request review commentforcedotcom/go-soql

Build out subfilter and OR logical operator support

 func marshalWhereClause(v interface{}, tableName string) (string, error) { 		fieldType := reflectedType.Field(i) 		clauseTag := fieldType.Tag.Get(SoqlTag) 		clauseKey := getClauseKey(clauseTag)-		fieldName := getFieldName(clauseTag, fieldType.Name)-		if fieldName == "" {-			return "", ErrInvalidTag-		}-		fn, ok := clauseBuilderMap[clauseKey]-		if !ok {-			return "", ErrInvalidTag-		}-		columnName := fieldName-		if tableName != "" {-			columnName = tableName + period + fieldName-		}-		partialClause, err := fn(field.Interface(), columnName)-		if err != nil {-			return "", err+		var partialClause string+		if clauseKey == Subquery {+			if field.Kind() != reflect.Struct {+				return "", ErrInvalidTag+			}+			partialClause, err = marshalWhereClause(field.Interface(), tableName, getJoiner(clauseTag))+			if err != nil {+				return "", err+			}++			partialClause = "(" + partialClause + ")"

Use openBrace and closeBrace constants instead of ( and ) string literals

t-margheim

comment created time in 2 months

issue closedforcedotcom/go-soql

*bool is not supported in buildEqualsClause

There is an issue with boolean conditions in buildEqualsClause: when bool fields are initialized, they default to "false" if a condition is not present, which Is not necessarily desirable behavior. I suggest to add *bool support and ignore those field if they're nil.

closed time in 2 months

dmaykov

issue commentforcedotcom/go-soql

*bool is not supported in buildEqualsClause

Closed by https://github.com/forcedotcom/go-soql/pull/12

dmaykov

comment created time in 2 months

push eventforcedotcom/go-soql

Atul Kshirsagar

commit sha 5a4ce53c16df04bdc355a61cc4a4b9de187c552b

Add support for pointer data types in comparison operators

view details

Atul Kshirsagar

commit sha 7eb58e078f5a9ec06430daf8b3805429531574b1

Merge pull request #12 from forcedotcom/issues/9/bool-ptr-support-equals Add support for pointer data types in comparison operators

view details

push time in 2 months

create barnchforcedotcom/go-soql

branch : issues/9/bool-ptr-support-equals

created branch time in 2 months

push eventforcedotcom/go-soql

Atul Kshirsagar

commit sha 4acb59b9acf19b550f151c76dcc074b8d332be35

Sanitize strings before using them in where clause

view details

Atul Kshirsagar

commit sha 1c94ce3a5a454a2a0b04b64f8cf7de7d9eb5e4ff

Merge pull request #11 from forcedotcom/issues/7/escape-single-quote Sanitize strings before using them in where clause

view details

push time in 2 months

PR merged forcedotcom/go-soql

Sanitize strings before using them in where clause cla:signed

Resolves #7

+93 -7

1 comment

2 changed files

atulkc

pr closed time in 2 months

issue closedforcedotcom/go-soql

Escape Single Quotes in WHERE clauses

Where clauses with ' are not escaped, causing 400 bad requests (in the best case) for the likeOperator.

The following code outputs: SELECT Name FROM Account WHERE Name LIKE '%Blips 'n' Chitz%' I would expect it to be: SELECT Name FROM Account WHERE Name LIKE '%Blips \'n\' Chitz%'

package main

import (
	"github.com/forcedotcom/go-soql"
	"log"
)

type Account struct {
	Name string `soql:"selectColumn,fieldName=Name" json:"Name"`
}

type AccountQueryCriteria struct {
	AccountName []string `soql:"likeOperator,fieldName=Name"`
}

type AccountSoqlQuery struct {
	SelectClause Account              `soql:"selectClause,tableName=Account"`
	WhereClause  AccountQueryCriteria `soql:"whereClause"`
}

func main() {
	soqlStruct := AccountSoqlQuery{
		SelectClause: Account{},
		WhereClause: AccountQueryCriteria{
			AccountName: []string{"Blips 'n' Chitz"},
		},
	}

	soqlQuery, err := soql.Marshal(soqlStruct)
	if err != nil {
		log.Fatal(err)
	}

	log.Println(soqlQuery)
}

closed time in 2 months

asgaines

issue closedforcedotcom/go-soql

Add support for limit and offset clause

Add support to tag int member with limitClause and offsetClause and include it in generated SOQL query. Here is how it should work:

type TestSoqlStruct struct {
	SelectClause NonNestedStruct   `soql:"selectClause,tableName=SM_SomeObject__c"`
	WhereClause  TestQueryCriteria `soql:"whereClause"`
	Limit        int               `soql:"limitClause"`
	Offset       int               `soql:"offsetClause"`
}
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"`
}

o use above structs to create SOQL query

soqlStruct := TestSoqlStruct{
    WhereClause: TestQueryCriteria {
        IncludeNamePattern: []string{"foo", "bar"},
        Roles: []string{"admin", "user"},
    }
    Limit: 10,
    Offset: 5,
}
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') LIMIT 10 OFFSET 5

closed time in 2 months

atulkc

issue commentforcedotcom/go-soql

Add support for limit and offset clause

Closed by https://github.com/forcedotcom/go-soql/pull/10

atulkc

comment created time in 2 months

push eventforcedotcom/go-soql

Tim Margheim

commit sha 2a9aa5de5c75352c5da8104e4d45ff459a950564

Add support for limit and offset clauses * limit implemented * working my way through offset * offset working, just need to handle child select case * corrections to comments * added test cases for limit 0, offset 0, and limit and offset * better variable name in marshalIntValue * Updated so that LIMIT and OFFSET can be 0 * update readme to document limit and offset

view details

Atul Kshirsagar

commit sha 4acb59b9acf19b550f151c76dcc074b8d332be35

Sanitize strings before using them in where clause

view details

push time in 2 months

push eventforcedotcom/go-soql

Tim Margheim

commit sha 2a9aa5de5c75352c5da8104e4d45ff459a950564

Add support for limit and offset clauses * limit implemented * working my way through offset * offset working, just need to handle child select case * corrections to comments * added test cases for limit 0, offset 0, and limit and offset * better variable name in marshalIntValue * Updated so that LIMIT and OFFSET can be 0 * update readme to document limit and offset

view details

push time in 2 months

PR merged forcedotcom/go-soql

#4 Limit and offset cla:signed

Added support for limit and offset with tests. I considered making offset on a child query an error since I don't believe Salesforce supports that behavior, but changed my mind so that select structs could be used as parents or children.

+458 -2

3 comments

4 changed files

t-margheim

pr closed time in 2 months

Pull request review commentforcedotcom/go-soql

#4 Limit and offset

 func marshalOrderByClause(v interface{}, tableName string, s interface{}) (strin  } +// v is the limit value provided+func marshalLimitClause(v interface{}) (string, error) {+	s, err := marshalIntValue(v)+	if err != nil {+		return "", ErrInvalidLimitClause+	}+	return s, nil+}++// v is the offset value provided+func marshalOffsetClause(v interface{}) (string, error) {+	s, err := marshalIntValue(v)+	if err != nil {+		return "", ErrInvalidOffsetClause+	}+	return s, nil+}++func marshalIntValue(v interface{}) (string, error) {+	limit, ok := v.(int)+	if !ok {+		return "", errors.New("invalid type")+	}+	if limit < 0 {+		return "", errors.New("invalid value")+	}++	var vString string+	if limit > 0 {

Also, please make sure you update README to include limitClause and offsetClause details. Adding it to Advanced Usage section is sufficient.

t-margheim

comment created time in 2 months

Pull request review commentforcedotcom/go-soql

#4 Limit and offset

 func marshalOrderByClause(v interface{}, tableName string, s interface{}) (strin  } +// v is the limit value provided+func marshalLimitClause(v interface{}) (string, error) {+	s, err := marshalIntValue(v)+	if err != nil {+		return "", ErrInvalidLimitClause+	}+	return s, nil+}++// v is the offset value provided+func marshalOffsetClause(v interface{}) (string, error) {+	s, err := marshalIntValue(v)+	if err != nil {+		return "", ErrInvalidOffsetClause+	}+	return s, nil+}++func marshalIntValue(v interface{}) (string, error) {+	limit, ok := v.(int)+	if !ok {+		return "", errors.New("invalid type")+	}+	if limit < 0 {+		return "", errors.New("invalid value")+	}++	var vString string+	if limit > 0 {

You are right, let's only allow int* for limitClause. For offsetClause it is ok to have both int and int*.

Adding func Int(v int) *int will feel little out of place for this library. I think we will leave it to the users of library to create pointers.

t-margheim

comment created time in 2 months

pull request commentforcedotcom/go-soql

#4 Limit and offset

Resolves #4

t-margheim

comment created time in 2 months

create barnchforcedotcom/go-soql

branch : issues/7/escape-single-quote

created branch time in 2 months

issue commentforcedotcom/go-soql

*bool is not supported in buildEqualsClause

Thanks for filing the issue. I will schedule this to be done in next couple of weeks. Sorry for the delay in response!

dmaykov

comment created time in 2 months

issue commentforcedotcom/go-soql

Escape Single Quotes in WHERE clauses

Thanks for filing the issue. I will schedule this to be done over next couple of weeks. Sorry for the delay in response.

asgaines

comment created time in 2 months

Pull request review commentforcedotcom/go-soql

#4 Limit and offset

 const ( 	WhereClause = "whereClause" 	// OrderByClause is the tag to be used when marking the string slice to be considered for order by clause 	OrderByClause = "orderByClause"+	// LimitClause is the tag to be used when marking the string slice to be considered for limit clause

Need to fix the comment to indicate that limit clause will be used for int and not string slice

t-margheim

comment created time in 2 months

Pull request review commentforcedotcom/go-soql

#4 Limit and offset

 const ( 	WhereClause = "whereClause" 	// OrderByClause is the tag to be used when marking the string slice to be considered for order by clause 	OrderByClause = "orderByClause"+	// LimitClause is the tag to be used when marking the string slice to be considered for limit clause+	LimitClause = "limitClause"+	// OffsetClause is the tag to be used when marking the string slice to be considered for offset clause

Need to fix the comment as indicated above for LimitClause

t-margheim

comment created time in 2 months

Pull request review commentforcedotcom/go-soql

#4 Limit and offset

 var _ = Describe("Marshaller", func() { 				Expect(actualQuery).To(Equal(expectedQuery)) 			}) 		})++		Context("when a struct with limit value is passed", func() {+			BeforeEach(func() {+				soqlStruct = TestSoqlLimitStruct{+					SelectClause: NestedStruct{},+					WhereClause: TestQueryCriteria{+						IncludeNamePattern: []string{"-db", "-dbmgmt"},+						Roles:              []string{"db", "dbmgmt"},+					},+					Limit: 5,+				}+				expectedQuery = "SELECT Id,Name__c,NonNestedStruct__r.Name,NonNestedStruct__r.SomeValue__c FROM SM_Logical_Host__c WHERE (Host_Name__c LIKE '%-db%' OR Host_Name__c LIKE '%-dbmgmt%') AND Role__r.Name IN ('db','dbmgmt') LIMIT 5"+			})++			It("returns properly constructed soql query", func() {+				Expect(err).ToNot(HaveOccurred())+				Expect(actualQuery).To(Equal(expectedQuery))+			})+		})++		Context("when a struct without limit value is passed", func() {+			BeforeEach(func() {+				soqlStruct = TestSoqlLimitStruct{+					SelectClause: NestedStruct{},+					WhereClause: TestQueryCriteria{+						IncludeNamePattern: []string{"-db", "-dbmgmt"},+						Roles:              []string{"db", "dbmgmt"},+					},+				}+				expectedQuery = "SELECT Id,Name__c,NonNestedStruct__r.Name,NonNestedStruct__r.SomeValue__c FROM SM_Logical_Host__c WHERE (Host_Name__c LIKE '%-db%' OR Host_Name__c LIKE '%-dbmgmt%') AND Role__r.Name IN ('db','dbmgmt')"+			})++			It("returns properly constructed soql query", func() {+				Expect(err).ToNot(HaveOccurred())+				Expect(actualQuery).To(Equal(expectedQuery))+			})+		})++		Context("when a struct with invalid limit type is passed", func() {+			BeforeEach(func() {+				soqlStruct = TestSoqlInvalidLimitStruct{+					SelectClause: NestedStruct{},+					WhereClause: TestQueryCriteria{+						IncludeNamePattern: []string{"-db", "-dbmgmt"},+						Roles:              []string{"db", "dbmgmt"},+					},+					Limit: "5",+				}+			})++			It("returns error", func() {+				Expect(err).To(Equal(ErrInvalidLimitClause))+			})+		})++		Context("when a struct with invalid limit value is passed", func() {+			BeforeEach(func() {+				soqlStruct = TestSoqlLimitStruct{+					SelectClause: NestedStruct{},+					WhereClause: TestQueryCriteria{+						IncludeNamePattern: []string{"-db", "-dbmgmt"},+						Roles:              []string{"db", "dbmgmt"},+					},+					Limit: -5,+				}+			})++			It("returns error", func() {+				Expect(err).To(Equal(ErrInvalidLimitClause))+			})+		})++		Context("when a struct with multiple limit values is passed", func() {+			BeforeEach(func() {+				soqlStruct = TestSoqlMultipleLimitStruct{+					SelectClause: NestedStruct{},+					WhereClause: TestQueryCriteria{+						IncludeNamePattern: []string{"-db", "-dbmgmt"},+						Roles:              []string{"db", "dbmgmt"},+					},+					Limit:     5,+					AlsoLimit: 15,+				}+			})++			It("returns error", func() {+				Expect(err).To(Equal(ErrMultipleLimitClause))+			})+		})++		Context("when a struct with limit inside a child relation is passed", func() {+			BeforeEach(func() {+				soqlStruct = TestSoqlChildRelationLimitStruct{+					SelectClause: ParentLimitStruct{+						ChildStruct: ChildLimitStruct{+							Limit: 1,+						},+					},+				}+				expectedQuery = "SELECT Id,Name__c,(SELECT Application_Versions__c.Id,Application_Versions__c.Version__c FROM Application_Versions__r LIMIT 1) FROM SM_Logical_Host__c"+			})++			It("returns properly constructed soql query", func() {+				Expect(err).ToNot(HaveOccurred())+				Expect(actualQuery).To(Equal(expectedQuery))+			})+		})++		Context("when a struct with limit inside a child relation is passed", func() {+			BeforeEach(func() {+				soqlStruct = TestSoqlChildRelationLimitStruct{+					SelectClause: ParentLimitStruct{+						ChildStruct: ChildLimitStruct{+							Limit: 10,+						},+					},+					Limit: 25,+				}+				expectedQuery = "SELECT Id,Name__c,(SELECT Application_Versions__c.Id,Application_Versions__c.Version__c FROM Application_Versions__r LIMIT 10) FROM SM_Logical_Host__c LIMIT 25"+			})++			It("returns properly constructed soql query", func() {+				Expect(err).ToNot(HaveOccurred())+				Expect(actualQuery).To(Equal(expectedQuery))+			})+		})++		Context("when a struct with offset value is passed", func() {+			BeforeEach(func() {+				soqlStruct = TestSoqlOffsetStruct{+					SelectClause: NestedStruct{},+					WhereClause: TestQueryCriteria{+						IncludeNamePattern: []string{"-db", "-dbmgmt"},+						Roles:              []string{"db", "dbmgmt"},+					},+					Offset: 5,+				}+				expectedQuery = "SELECT Id,Name__c,NonNestedStruct__r.Name,NonNestedStruct__r.SomeValue__c FROM SM_Logical_Host__c WHERE (Host_Name__c LIKE '%-db%' OR Host_Name__c LIKE '%-dbmgmt%') AND Role__r.Name IN ('db','dbmgmt') OFFSET 5"+			})++			It("returns properly constructed soql query", func() {+				Expect(err).ToNot(HaveOccurred())+				Expect(actualQuery).To(Equal(expectedQuery))+			})+		})++		Context("when a struct without offset value is passed", func() {+			BeforeEach(func() {+				soqlStruct = TestSoqlOffsetStruct{+					SelectClause: NestedStruct{},+					WhereClause: TestQueryCriteria{+						IncludeNamePattern: []string{"-db", "-dbmgmt"},+						Roles:              []string{"db", "dbmgmt"},+					},+				}+				expectedQuery = "SELECT Id,Name__c,NonNestedStruct__r.Name,NonNestedStruct__r.SomeValue__c FROM SM_Logical_Host__c WHERE (Host_Name__c LIKE '%-db%' OR Host_Name__c LIKE '%-dbmgmt%') AND Role__r.Name IN ('db','dbmgmt')"+			})++			It("returns properly constructed soql query", func() {+				Expect(err).ToNot(HaveOccurred())+				Expect(actualQuery).To(Equal(expectedQuery))+			})+		})++		Context("when a struct with invalid offset type is passed", func() {+			BeforeEach(func() {+				soqlStruct = TestSoqlInvalidOffsetStruct{+					SelectClause: NestedStruct{},+					WhereClause: TestQueryCriteria{+						IncludeNamePattern: []string{"-db", "-dbmgmt"},+						Roles:              []string{"db", "dbmgmt"},+					},+					Offset: "5",+				}+			})++			It("returns error", func() {+				Expect(err).To(Equal(ErrInvalidOffsetClause))+			})+		})++		Context("when a struct with invalid offset value is passed", func() {+			BeforeEach(func() {+				soqlStruct = TestSoqlOffsetStruct{+					SelectClause: NestedStruct{},+					WhereClause: TestQueryCriteria{+						IncludeNamePattern: []string{"-db", "-dbmgmt"},+						Roles:              []string{"db", "dbmgmt"},+					},+					Offset: -5,+				}+			})++			It("returns error", func() {+				Expect(err).To(Equal(ErrInvalidOffsetClause))+			})+		})++		Context("when a struct with multiple offset values is passed", func() {+			BeforeEach(func() {+				soqlStruct = TestSoqlMultipleOffsetStruct{+					SelectClause: NestedStruct{},+					WhereClause: TestQueryCriteria{+						IncludeNamePattern: []string{"-db", "-dbmgmt"},+						Roles:              []string{"db", "dbmgmt"},+					},+					Offset:     5,+					AlsoOffset: 15,+				}+			})++			It("returns error", func() {+				Expect(err).To(Equal(ErrMultipleOffsetClause))+			})+		})

I think following test cases should be added:

  1. Both limit and offset are present.
  2. When offset is 0
  3. When limit is 0
t-margheim

comment created time in 2 months

Pull request review commentforcedotcom/go-soql

#4 Limit and offset

 func marshalOrderByClause(v interface{}, tableName string, s interface{}) (strin  } +// v is the limit value provided+func marshalLimitClause(v interface{}) (string, error) {+	s, err := marshalIntValue(v)+	if err != nil {+		return "", ErrInvalidLimitClause+	}+	return s, nil+}++// v is the offset value provided+func marshalOffsetClause(v interface{}) (string, error) {+	s, err := marshalIntValue(v)+	if err != nil {+		return "", ErrInvalidOffsetClause+	}+	return s, nil+}++func marshalIntValue(v interface{}) (string, error) {+	limit, ok := v.(int)+	if !ok {+		return "", errors.New("invalid type")+	}+	if limit < 0 {+		return "", errors.New("invalid value")+	}++	var vString string+	if limit > 0 {

Since marshalIntValue will be used for both offset and limit this check would prevent us from having OFFSET 0 in the query.

t-margheim

comment created time in 2 months

more