diff --git a/internal/jet/column_list.go b/internal/jet/column_list.go index 8483c76..3ff829c 100644 --- a/internal/jet/column_list.go +++ b/internal/jet/column_list.go @@ -11,6 +11,28 @@ func (cl ColumnList) SET(expression Expression) ColumnAssigment { } } +// Except will create new column list in which columns contained in excluded column names are removed +func (cl ColumnList) Except(excludedColumns ...Column) ColumnList { + excludedColumnList := UnwidColumnList(excludedColumns) + excludedColumnNames := map[string]bool{} + + for _, excludedColumn := range excludedColumnList { + excludedColumnNames[excludedColumn.Name()] = true + } + + var ret ColumnList + + for _, column := range cl { + if excludedColumnNames[column.Name()] { + continue + } + + ret = append(ret, column) + } + + return ret +} + func (cl ColumnList) fromImpl(subQuery SelectTable) Projection { newProjectionList := ProjectionList{} diff --git a/tests/postgres/select_test.go b/tests/postgres/select_test.go index 59fc44a..7b7bf00 100644 --- a/tests/postgres/select_test.go +++ b/tests/postgres/select_test.go @@ -1992,3 +1992,66 @@ LIMIT 1; require.Equal(t, dest, dest2) }) } + +func TestSelectColumnListWithExcludedColumns(t *testing.T) { + + t.Run("one column", func(t *testing.T) { + stmt := SELECT( + Address.AllColumns.Except(Address.LastUpdate), + ).FROM( + Address, + ) + + testutils.AssertDebugStatementSql(t, stmt, ` +SELECT address.address_id AS "address.address_id", + address.address AS "address.address", + address.address2 AS "address.address2", + address.district AS "address.district", + address.city_id AS "address.city_id", + address.postal_code AS "address.postal_code", + address.phone AS "address.phone" +FROM dvds.address; +`) + var dest []model.Address + require.NoError(t, stmt.Query(db, &dest)) + require.Len(t, dest, 603) + }) + + t.Run("multiple columns", func(t *testing.T) { + expectedSQL := ` +SELECT address.address_id AS "address.address_id", + address.address AS "address.address", + address.address2 AS "address.address2", + address.district AS "address.district", + address.city_id AS "address.city_id" +FROM dvds.address; +` + // list of columns + stmt := SELECT( + Address.AllColumns.Except(Address.PostalCode, Address.Phone, Address.LastUpdate), + ).FROM( + Address, + ) + testutils.AssertDebugStatementSql(t, stmt, expectedSQL) + + // column list + excludedColumns := ColumnList{Address.PostalCode, Address.Phone, Address.LastUpdate, Film.Title} // Film.Title is ignored + stmt = SELECT( + Address.AllColumns.Except(excludedColumns), + ).FROM(Address) + + testutils.AssertDebugStatementSql(t, stmt, expectedSQL) + + // column list with just column names + excludedColumns = ColumnList{StringColumn("postal_code"), StringColumn("phone"), TimestampColumn("last_update")} + stmt = SELECT( + Address.AllColumns.Except(excludedColumns), + ).FROM(Address) + + testutils.AssertDebugStatementSql(t, stmt, expectedSQL) + + var dest []model.Address + require.NoError(t, stmt.Query(db, &dest)) + require.Len(t, dest, 603) + }) +}