go-sqlmock icon indicating copy to clipboard operation
go-sqlmock copied to clipboard

Question: how to use with postgres text[] field?

Open shaunc opened this issue 6 years ago • 5 comments
trafficstars

My code uses pg.Array to read a text[] field. Can I use this package to test this code? ... if so, how?

Thanks!

shaunc avatar Oct 21 '19 17:10 shaunc

Hi, it requires a ValueConverter registered through the sqlmock.Option. if the driver you use provides those ValueConverters, you should just register them. Otherwise you may need to copy them from the source code. As far as I've heard it works fine, is just the arrays are not the standard values in go standard database driver

l3pp4rd avatar Dec 09 '19 07:12 l3pp4rd

@shaunc I add the same challenge to convert my array of strings into psql array. I used pq.Array from "github.com/lib/pq" against the value of a row I wanted sqlmock to return on a select statement. Hope this can be helpful

guillermo-menjivar avatar Mar 01 '20 04:03 guillermo-menjivar

@shaunc, +1 to @guillermo-menjivar, I got inspired by his comment above, but I did slightly differently. Since I don't wish to introduce a whole new package into my project just for this. I wrote a function to convert my []string into something like following stringForQuery := "{\"firstString\",\"secondString\"}" Now both my Postgres and Sqlmock are working.

mintyknight avatar Nov 14 '22 13:11 mintyknight

Using a ValueConverter did the trick just as @l3pp4rd suggested. This is the working code, assuming you are using pq.StringArray(…) in your code:

// StringArrayConverter is a database/sql driver.ValueConverter implementation
// that is used in our unit tests to teach sqlmock about the pq.StringArray type.
type StringArrayConverter struct{}

// ConvertValue converts a value to a driver Value.
func (s StringArrayConverter) ConvertValue(v any) (driver.Value, error) {
	switch x := v.(type) {
	case pq.StringArray:
		return []string(x), nil
	default:
		return x, nil
	}
}

func TestRepository(t *testing.T) {
	db, mock, err := sqlmock.New(sqlmock.ValueConverterOption(new(StringArrayConverter)))
	…
}

fgrosse avatar Jul 27 '23 07:07 fgrosse

@fgrosse Your suggestions doesn't seems to be working.

rows := sqlmock.NewRows([]string{"ns_tenant_id", "role_id", "rbac_version", "obfuscation_fields", "users_scope", "case_sensitive_groups", "groups_scope_exclude", "groups_scope", "app_instance_scope", "ou_scope", "scope_query", "insertion_timestamp"}).
				AddRow(1, 1, "v1", pq.StringArray{"field1", "field2"}, pq.StringArray{"user1", "user2"}, 0, 0, pq.StringArray{"group1", "group2"}, pq.StringArray{"app1", "app2"}, pq.StringArray{"ou1", "ou2"}, "query", "2023-08-07T00:00:00Z")

			query := fmt.Sprintf("SELECT (.+) FROM .table1 WHERE ns_tenant_id = %d", test.nsTenantID)
			mock.ExpectQuery(query).WillReturnRows(rows)

the error is *fmt.wrapError(&fmt.wrapError{msg:"sql: Scan error on column index 3, name \"obfuscation_fields\": unsupported Scan, storing driver.Value type string into type *[]string", err:(*errors.errorString)(0x14000298ec0)})

Is this the correct way to mock?

ns-tdemelocosta avatar Aug 11 '23 20:08 ns-tdemelocosta