Skip to content

Commit 8bc3022

Browse files
authored
feat: implement column renaming and casting (#29)
* feat: implement value casting * feat: implement column renaming
1 parent 8a5b17e commit 8bc3022

File tree

2 files changed

+72
-1
lines changed

2 files changed

+72
-1
lines changed

integration_select_test.go

+21
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,27 @@ func testSelect_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
394394
}
395395
})
396396

397+
t.Run("SelectWithAdaptingColumns", func(t *testing.T) {
398+
tc := createTestContext(t)
399+
defer tc.CleanUp(t)
400+
401+
tc.ExecuteSQL(t, "CREATE TABLE test (id int, s text, d text)")
402+
tc.ExecuteSQL(t, `INSERT INTO test (id, s, d) VALUES (1, "1", "a"), (2, "2", "a"), (3, "3", "a")`)
403+
404+
client := tc.Client()
405+
res, _, err := client.From("test").Select("id_str:id::text, s::int, d_text:d", "", false).
406+
Execute()
407+
assert.NoError(t, err)
408+
409+
var rv []map[string]interface{}
410+
tc.DecodeResult(t, res, &rv)
411+
assert.Len(t, rv, 3)
412+
for idx, row := range rv {
413+
assert.EqualValues(t, fmt.Sprint(idx+1), row["id_str"])
414+
assert.EqualValues(t, idx+1, row["s"])
415+
assert.EqualValues(t, "a", row["d_text"])
416+
}
417+
})
397418
}
398419

399420
func TestSelect_SingleTable(t *testing.T) {

query.go

+51-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ const (
2727
logicalOperatorNot = "not"
2828
logicalOperatorAnd = "and"
2929
logicalOperatorOr = "or"
30+
31+
doubleColonCastingOperator = "::" // NOTE: this is a PostgreSQL specific operator
32+
singleColonRenameOperator = ":"
3033
)
3134

3235
type CompiledQuery struct {
@@ -334,14 +337,61 @@ func (c *queryCompiler) CompileAsDelete(table string) (CompiledQuery, error) {
334337
return rv, nil
335338
}
336339

340+
func getSelectResultColumn(columnName string) string {
341+
// newName:name::text
342+
// => cast(name as text) as newName
343+
344+
var (
345+
columnType string
346+
targetColumnName string
347+
)
348+
349+
if strings.Contains(columnName, doubleColonCastingOperator) {
350+
ps := strings.SplitN(columnName, doubleColonCastingOperator, 2)
351+
if len(ps) == 2 {
352+
// is a valid casting call
353+
columnName = ps[0]
354+
columnType = ps[1]
355+
}
356+
// NOTE: if it's not a valid casting, since the columnType is still empty,
357+
// no casting will be applied
358+
}
359+
360+
if strings.Contains(columnName, singleColonRenameOperator) {
361+
ps := strings.SplitN(columnName, singleColonRenameOperator, 2)
362+
if len(ps) == 2 {
363+
// is a valid renaming call
364+
targetColumnName = ps[0]
365+
columnName = ps[1]
366+
}
367+
// NOTE: if it's not a valid renaming, since the targetColumnName is still empty,
368+
// no renaming will be applied
369+
}
370+
371+
if columnType == "" {
372+
if targetColumnName == "" {
373+
return columnName
374+
}
375+
return fmt.Sprintf("%s as %s", columnName, targetColumnName)
376+
} else {
377+
if targetColumnName == "" {
378+
targetColumnName = columnName
379+
}
380+
return fmt.Sprintf("cast(%s as %s) as %s", columnName, columnType, targetColumnName)
381+
}
382+
}
383+
337384
func (c *queryCompiler) getSelectResultColumns() []string {
338385
v := c.getQueryParameter(queryParameterNameSelect)
339386
if v == "" {
340387
return []string{"*"}
341388
}
342389

343390
vs := strings.Split(v, ",")
344-
// TOOD: support renaming, casting
391+
// TOOD: support renaming
392+
for idx := range vs {
393+
vs[idx] = getSelectResultColumn(vs[idx])
394+
}
345395

346396
return vs
347397
}

0 commit comments

Comments
 (0)