Skip to content

Commit

Permalink
Adds DefaultIfEmpty function (#95)
Browse files Browse the repository at this point in the history
Co-authored-by: Cleiton Marques Souza <[email protected]>
  • Loading branch information
cleitonmarx and Cleiton Marques Souza authored Jun 5, 2020
1 parent 7a0b206 commit 55c110a
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 0 deletions.
33 changes: 33 additions & 0 deletions defaultifempty.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package linq

// DefaultIfEmpty returns the elements of the specified sequence
// if the sequence is empty.
func (q Query) DefaultIfEmpty(defaultValue interface{}) Query {
return Query{
Iterate: func() Iterator {
next := q.Iterate()
state := 1

return func() (item interface{}, ok bool) {
switch state {
case 1:
item, ok = next()
if ok {
state = 2
} else {
item = defaultValue
ok = true
state = -1
}
return
case 2:
for item, ok = next(); ok; item, ok = next() {
return
}
return
}
return
}
},
}
}
25 changes: 25 additions & 0 deletions defaultifempty_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package linq

import (
"testing"
)

func TestDefaultIfEmpty(t *testing.T) {
defaultValue := 0
tests := []struct {
input []interface{}
want []interface{}
}{
{[]interface{}{}, []interface{}{defaultValue}},
{[]interface{}{1, 2, 3, 4, 5}, []interface{}{1, 2, 3, 4, 5}},
}

for _, test := range tests {
q := From(test.input).DefaultIfEmpty(defaultValue)

if !validateQuery(q, test.want) {
t.Errorf("From(%v).DefaultIfEmpty(%v)=%v expected %v", test.input, defaultValue, toSlice(q), test.want)
}
}

}
70 changes: 70 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,76 @@ func ExampleQuery_CountWith() {
// 6
}

// The following example demonstrates how to use the DefaultIfEmpty
// method on the results of a group join to perform a left outer join.
//
// The first step in producing a left outer join of two collections is to perform
// an inner join by using a group join. In this example, the list of Person objects
// is inner-joined to the list of Pet objects based on a Person object that matches Pet.Owner.
//
// The second step is to include each element of the first (left) collection in the
// result set even if that element has no matches in the right collection.
// This is accomplished by calling DefaultIfEmpty on each sequence of matching
// elements from the group join.
// In this example, DefaultIfEmpty is called on each sequence of matching Pet elements.
// The method returns a collection that contains a single, default value if the sequence
// of matching Pet elements is empty for any Person element, thereby ensuring that each
// Person element is represented in the result collection.
func ExampleQuery_DefaultIfEmpty() {
type Person struct {
FirstName string
LastName string
}

type Pet struct {
Name string
Owner Person
}

magnus := Person{FirstName: "Magnus", LastName: "Hedlund"}
terry := Person{FirstName: "Terry", LastName: "Adams"}
charlotte := Person{FirstName: "Charlotte", LastName: "Weiss"}
arlene := Person{FirstName: "Arlene", LastName: "Huff"}

barley := Pet{Name: "Barley", Owner: terry}
boots := Pet{Name: "Boots", Owner: terry}
whiskers := Pet{Name: "Whiskers", Owner: charlotte}
bluemoon := Pet{Name: "Blue Moon", Owner: terry}
daisy := Pet{Name: "Daisy", Owner: magnus}

// Create two lists.
people := []Person{magnus, terry, charlotte, arlene}
pets := []Pet{barley, boots, whiskers, bluemoon, daisy}

results := []string{}
From(people).
GroupJoinT(
From(pets),
func(person Person) Person { return person },
func(pet Pet) Person { return pet.Owner },
func(person Person, pets []Pet) Group { return Group{Key: person, Group: From(pets).Results()} },
).
SelectManyByT(
func(g Group) Query { return From(g.Group).DefaultIfEmpty(Pet{}) },
func(pet Pet, group Group) string {
return fmt.Sprintf("%s: %s", group.Key.(Person).FirstName, pet.Name)
},
).
ToSlice(&results)

for _, s := range results {
fmt.Println(s)
}
// Output:
// Magnus: Daisy
// Terry: Barley
// Terry: Boots
// Terry: Blue Moon
// Charlotte: Whiskers
// Arlene:

}

//The following code example demonstrates how to use Distinct
//to return distinct elements from a slice of integers.
func ExampleQuery_Distinct() {
Expand Down

0 comments on commit 55c110a

Please sign in to comment.