From a506a96d6a5769abe32cc70913e012133a07659c Mon Sep 17 00:00:00 2001 From: go-jet Date: Mon, 10 Jan 2022 16:43:17 +0100 Subject: [PATCH] Add DISTINCT operator support --- internal/jet/operators.go | 5 +++ mysql/operators.go | 3 ++ postgres/operators.go | 3 ++ sqlite/operators.go | 3 ++ tests/mysql/select_test.go | 62 +++++++++++++++++++++++++++++++++++ tests/postgres/select_test.go | 60 +++++++++++++++++++++++++++++++++ tests/sqlite/select_test.go | 61 ++++++++++++++++++++++++++++++++++ 7 files changed, 197 insertions(+) diff --git a/internal/jet/operators.go b/internal/jet/operators.go index 19173a6..b73a451 100644 --- a/internal/jet/operators.go +++ b/internal/jet/operators.go @@ -173,3 +173,8 @@ func (c *caseOperatorImpl) serialize(statement StatementType, out *SQLBuilder, o out.WriteString("END)") } + +// DISTINCT operator can be used to return distinct values of expr +func DISTINCT(expr Expression) Expression { + return newPrefixOperatorExpression(expr, "DISTINCT") +} diff --git a/mysql/operators.go b/mysql/operators.go index 5585511..9591a92 100644 --- a/mysql/operators.go +++ b/mysql/operators.go @@ -7,3 +7,6 @@ var NOT = jet.NOT // BIT_NOT inverts every bit in integer expression result var BIT_NOT = jet.BIT_NOT + +// DISTINCT operator can be used to return distinct values of expr +var DISTINCT = jet.DISTINCT diff --git a/postgres/operators.go b/postgres/operators.go index 04c8b23..dcce3e0 100644 --- a/postgres/operators.go +++ b/postgres/operators.go @@ -7,3 +7,6 @@ var NOT = jet.NOT // BIT_NOT inverts every bit in integer expression result var BIT_NOT = jet.BIT_NOT + +// DISTINCT operator can be used to return distinct values of expr +var DISTINCT = jet.DISTINCT diff --git a/sqlite/operators.go b/sqlite/operators.go index 8ebecbf..58d9cd9 100644 --- a/sqlite/operators.go +++ b/sqlite/operators.go @@ -7,3 +7,6 @@ var NOT = jet.NOT // BIT_NOT inverts every bit in integer expression result var BIT_NOT = jet.BIT_NOT + +// DISTINCT operator can be used to return distinct values of expr +var DISTINCT = jet.DISTINCT diff --git a/tests/mysql/select_test.go b/tests/mysql/select_test.go index a1dc3fc..5ae7280 100644 --- a/tests/mysql/select_test.go +++ b/tests/mysql/select_test.go @@ -153,6 +153,68 @@ ORDER BY payment.customer_id, SUM(payment.amount) ASC; requireLogged(t, query) } +func TestAggregateFunctionDistinct(t *testing.T) { + stmt := SELECT( + Payment.CustomerID, + + COUNT(DISTINCT(Payment.Amount)).AS("distinct.count"), + SUM(DISTINCT(Payment.Amount)).AS("distinct.sum"), + AVG(DISTINCT(Payment.Amount)).AS("distinct.avg"), + MIN(DISTINCT(Payment.PaymentDate)).AS("distinct.first_payment_date"), + MAX(DISTINCT(Payment.PaymentDate)).AS("distinct.last_payment_date"), + ).FROM( + Payment, + ).WHERE( + Payment.CustomerID.EQ(Int(1)), + ).GROUP_BY( + Payment.CustomerID, + ) + + testutils.AssertDebugStatementSql(t, stmt, ` +SELECT payment.customer_id AS "payment.customer_id", + COUNT(DISTINCT payment.amount) AS "distinct.count", + SUM(DISTINCT payment.amount) AS "distinct.sum", + AVG(DISTINCT payment.amount) AS "distinct.avg", + MIN(DISTINCT payment.payment_date) AS "distinct.first_payment_date", + MAX(DISTINCT payment.payment_date) AS "distinct.last_payment_date" +FROM dvds.payment +WHERE payment.customer_id = 1 +GROUP BY payment.customer_id; +`) + + type Distinct struct { + model.Payment + + Count int64 + Sum float64 + Avg float64 + FirstPaymentDate time.Time + LastPaymentDate time.Time + } + + var dest Distinct + + err := stmt.Query(db, &dest) + require.NoError(t, err) + testutils.AssertJSON(t, dest, ` +{ + "PaymentID": 0, + "CustomerID": 1, + "StaffID": 0, + "RentalID": null, + "Amount": 0, + "PaymentDate": "0001-01-01T00:00:00Z", + "LastUpdate": "0001-01-01T00:00:00Z", + "Count": 8, + "Sum": 38.92, + "Avg": 4.865, + "FirstPaymentDate": "2005-05-25T11:30:37Z", + "LastPaymentDate": "2005-08-22T20:03:46Z" +} +`) + +} + func TestSubQuery(t *testing.T) { rRatingFilms := Film. diff --git a/tests/postgres/select_test.go b/tests/postgres/select_test.go index 87edaf7..5a18ceb 100644 --- a/tests/postgres/select_test.go +++ b/tests/postgres/select_test.go @@ -1191,6 +1191,66 @@ ORDER BY customer.customer_id, SUM(payment.amount) ASC; testutils.AssertJSONFile(t, dest, "./testdata/results/postgres/customer_payment_sum.json") } +func TestAggregateFunctionDistinct(t *testing.T) { + stmt := SELECT( + Payment.CustomerID, + + COUNT(DISTINCT(Payment.Amount)).AS("distinct.count"), + SUM(DISTINCT(Payment.Amount)).AS("distinct.sum"), + AVG(DISTINCT(Payment.Amount)).AS("distinct.avg"), + MIN(DISTINCT(Payment.PaymentDate)).AS("distinct.first_payment_date"), + MAX(DISTINCT(Payment.PaymentDate)).AS("distinct.last_payment_date"), + ).FROM( + Payment, + ).WHERE( + Payment.CustomerID.EQ(Int(1)), + ).GROUP_BY( + Payment.CustomerID, + ) + + testutils.AssertDebugStatementSql(t, stmt, ` +SELECT payment.customer_id AS "payment.customer_id", + COUNT(DISTINCT payment.amount) AS "distinct.count", + SUM(DISTINCT payment.amount) AS "distinct.sum", + AVG(DISTINCT payment.amount) AS "distinct.avg", + MIN(DISTINCT payment.payment_date) AS "distinct.first_payment_date", + MAX(DISTINCT payment.payment_date) AS "distinct.last_payment_date" +FROM dvds.payment +WHERE payment.customer_id = 1 +GROUP BY payment.customer_id; +`) + + type Distinct struct { + model.Payment + + Count int64 + Sum float64 + Avg float64 + FirstPaymentDate time.Time + LastPaymentDate time.Time + } + + var dest Distinct + + err := stmt.Query(db, &dest) + require.NoError(t, err) + testutils.AssertJSON(t, dest, ` +{ + "PaymentID": 0, + "CustomerID": 1, + "StaffID": 0, + "RentalID": 0, + "Amount": 0, + "PaymentDate": "0001-01-01T00:00:00Z", + "Count": 8, + "Sum": 38.92, + "Avg": 4.865, + "FirstPaymentDate": "2007-02-14T23:22:38.996577Z", + "LastPaymentDate": "2007-04-30T01:10:44.996577Z" +} +`) +} + func TestSelectGroupBy2(t *testing.T) { expectedSQL := ` SELECT customer.customer_id AS "customer.customer_id", diff --git a/tests/sqlite/select_test.go b/tests/sqlite/select_test.go index 95527f1..ce31c76 100644 --- a/tests/sqlite/select_test.go +++ b/tests/sqlite/select_test.go @@ -143,6 +143,67 @@ ORDER BY payment.customer_id, SUM(payment.amount) ASC; requireLogged(t, query) } +func TestAggregateFunctionDistinct(t *testing.T) { + stmt := SELECT( + Payment.CustomerID, + + COUNT(DISTINCT(Payment.Amount)).AS("distinct.count"), + SUM(DISTINCT(Payment.Amount)).AS("distinct.sum"), + AVG(DISTINCT(Payment.Amount)).AS("distinct.avg"), + MIN(DISTINCT(Payment.PaymentDate)).AS("distinct.first_payment_date"), + MAX(DISTINCT(Payment.PaymentDate)).AS("distinct.last_payment_date"), + ).FROM( + Payment, + ).WHERE( + Payment.CustomerID.EQ(Int(1)), + ).GROUP_BY( + Payment.CustomerID, + ) + + testutils.AssertDebugStatementSql(t, stmt, ` +SELECT payment.customer_id AS "payment.customer_id", + COUNT(DISTINCT payment.amount) AS "distinct.count", + SUM(DISTINCT payment.amount) AS "distinct.sum", + AVG(DISTINCT payment.amount) AS "distinct.avg", + MIN(DISTINCT payment.payment_date) AS "distinct.first_payment_date", + MAX(DISTINCT payment.payment_date) AS "distinct.last_payment_date" +FROM payment +WHERE payment.customer_id = 1 +GROUP BY payment.customer_id; +`) + + type Distinct struct { + model.Payment + + Count int64 + Sum float64 + Avg float64 + FirstPaymentDate time.Time + LastPaymentDate time.Time + } + + var dest Distinct + + err := stmt.Query(db, &dest) + require.NoError(t, err) + testutils.AssertJSON(t, dest, ` +{ + "PaymentID": 0, + "CustomerID": 1, + "StaffID": 0, + "RentalID": null, + "Amount": 0, + "PaymentDate": "0001-01-01T00:00:00Z", + "LastUpdate": "0001-01-01T00:00:00Z", + "Count": 8, + "Sum": 38.92000000000001, + "Avg": 4.865000000000001, + "FirstPaymentDate": "2005-05-25T11:30:37Z", + "LastPaymentDate": "2005-08-22T20:03:46Z" +} +`) +} + func TestSubQuery(t *testing.T) { rRatingFilms :=