Documentation
¶
Overview ¶
Package query provides primitives for querying slices and user-defined collections.
Example ¶
package main
import (
"fmt"
)
type Author struct {
AuthorID int
Name string
}
type AuthorBook struct {
AuthorID int
BookID int
}
type Book struct {
BookID int
Title string
Year int
}
type NameBookID struct {
Name string
BookID int
}
type AuthorTitleYear struct {
Author string
Title string
Year int
}
func (a AuthorTitleYear) String() string {
return fmt.Sprintf("{%v: %v (%v)}", a.Author, a.Title, a.Year)
}
func main() {
// Authors table:
authors := []T{
Author{1, "Austen, Jane"},
Author{2, "Brontë, Emily"},
Author{3, "Hunter, Rachel"},
}
// Books table:
books := []T{
Book{1, "Sense & Sensibility", 1811},
Book{2, "Pride & Prejudice", 1813},
Book{3, "Mansfield Park", 1814},
Book{4, "Emma", 1815},
Book{5, "Persuasion", 1817},
Book{6, "Northanger Abbey", 1817},
Book{7, "Sanditon", 1817},
Book{8, "Wuthering Heights", 1847},
Book{9, "Letitia, or, The Castle without a Spectre", 1801},
Book{10, "The History of the Grubthorpe Family", 1802},
Book{11, "Letters from Mrs Palmerstone to her Daughter, Inculcating Morality by Entertaining Narratives", 1803},
Book{12, "The Unexpected Legacy", 1804},
Book{13, "Family Annals", 1807},
Book{14, "The Schoolmistress", 1811},
}
// Authors to books table:
author2Books := []T{
AuthorBook{1, 1},
AuthorBook{1, 2},
AuthorBook{1, 3},
AuthorBook{1, 4},
AuthorBook{1, 5},
AuthorBook{1, 6},
AuthorBook{1, 7},
AuthorBook{2, 8},
AuthorBook{3, 9},
AuthorBook{3, 10},
AuthorBook{3, 11},
AuthorBook{3, 12},
AuthorBook{3, 13},
AuthorBook{3, 14},
}
// Print all authors, title of their books, published between 1804 and 1815:
query := From([]T(authors)).
Join(From(author2Books),
func(e T) interface{} {
return e.(Author).AuthorID
}, func(e T) interface{} {
return e.(AuthorBook).AuthorID
}, func(e1, e2 interface{}) interface{} {
return NameBookID{e1.(Author).Name, e2.(AuthorBook).BookID}
}).
Join(From(books),
func(e T) interface{} {
return e.(NameBookID).BookID
}, func(e T) interface{} {
return e.(Book).BookID
}, func(e1, e2 interface{}) interface{} {
return AuthorTitleYear{e1.(NameBookID).Name, e2.(Book).Title, e2.(Book).Year}
}).
Sort(
func(e1, e2 T) bool {
return e1.(AuthorTitleYear).Year > e2.(AuthorTitleYear).Year
},
func(e1, e2 T) bool {
return e1.(AuthorTitleYear).Author < e2.(AuthorTitleYear).Author
}).
Where(
func(e T) bool {
return e.(AuthorTitleYear).Year >= 1804
}, func(e T) bool {
return e.(AuthorTitleYear).Year <= 1815
})
fmt.Printf("%v\n", query)
}
Output: [{Austen, Jane: Emma (1815)} {Austen, Jane: Mansfield Park (1814)} {Austen, Jane: Pride & Prejudice (1813)} {Austen, Jane: Sense & Sensibility (1811)} {Hunter, Rachel: The Schoolmistress (1811)} {Hunter, Rachel: Family Annals (1807)} {Hunter, Rachel: The Unexpected Legacy (1804)}]
Index ¶
- func ToSlice(q *Query) []interface{}
- type Iterator
- type Query
- func (q *Query) Any(f ...func(e T) bool) bool
- func (q *Query) At(i int) (elem T)
- func (q *Query) Contains(e T) bool
- func (q *Query) Every(f ...func(e T) bool) bool
- func (q *Query) Expand(f func(e T) []T) *Query
- func (q *Query) First() (first T)
- func (q *Query) Fold(v T, f func(v, e T) interface{}) interface{}
- func (q *Query) ForEach(f func(e T))
- func (q *Query) IsEmpty() bool
- func (q *Query) Join(inner *Query, outKeySel func(e T) interface{}, innKeySel func(e T) interface{}, ...) *Query
- func (q *Query) Last() (last T)
- func (q *Query) MapTo(f func(e T) T) *Query
- func (q *Query) Reduce(f func(v, e T) interface{}) interface{}
- func (q *Query) Skip(n int) *Query
- func (q *Query) Sort(f ...func(e, f T) bool) *Query
- func (q *Query) String() string
- func (q *Query) Take(n int) *Query
- func (q *Query) Where(f ...func(e T) bool) *Query
- type T
Examples ¶
- Package
- From
- Query.Any (GreatherThan)
- Query.Any (Odd)
- Query.At (Found)
- Query.At (NotFound)
- Query.Contains (Found)
- Query.Contains (NotFound)
- Query.Every (AllEven)
- Query.Every (AllOdd)
- Query.Expand (Duplicate)
- Query.Expand (Identity)
- Query.Expand (Null)
- Query.Expand (Odd)
- Query.First (Empty)
- Query.First (Found)
- Query.Fold (Sum)
- Query.ForEach (Append)
- Query.ForEach (Count)
- Query.ForEach (Sum)
- Query.IsEmpty (Empty)
- Query.IsEmpty (NotEmpty)
- Query.Join (Inner)
- Query.Last (Empty)
- Query.Last (Found)
- Query.MapTo (Add)
- Query.MapTo (AddToEven)
- Query.Reduce (Sum)
- Query.Skip (Empty)
- Query.Skip (Found)
- Query.Sort (Decreasing)
- Query.Sort (Increasing)
- Query.Take (All)
- Query.Take (Some)
- Query.Where (GreaterThan)
- Query.Where (LessThan)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Query ¶
type Query struct {
Iterate func() Iterator
}
Query is the type returned from query functions. It can be iterated manually.
func From ¶
From initializes a query with passed slice as the source.
Example ¶
q := From([]T{1, 3, 5, 7, 9})
fmt.Printf("Got from query: %v\n", q)
Output: Got from query: [1 3 5 7 9]
func (*Query) Any ¶
Any checks whether any element of this collection satisfies all predicates.
Checks every element in iteration order, and returns true if any of them make test return true, otherwise returns false.
Example (GreatherThan) ¶
isEven := func(e T) bool {
return e.(int)&1 == 0
}
greaterThan0 := func(e T) bool {
return e.(int) > 0
}
q := From([]T{1, 3, 6, 7, 9})
v := q.Any(isEven, greaterThan0)
fmt.Printf("An even number > 3 was found: %v\n", v)
Output: An even number > 3 was found: true
Example (Odd) ¶
isEven := func(e T) bool {
return e.(int)&1 == 0
}
greaterThan0 := func(e T) bool {
return e.(int) > 0
}
q := From([]T{1, 3, 5, 7, 9})
v := q.Any(isEven, greaterThan0)
fmt.Printf("An even number > 3 was found: %v\n", v)
Output: An even number > 3 was found: false
func (*Query) At ¶
At returns the ith element.
The index i must be non-negative and less than length. Index zero represents the first element (so Query.At(0) is equivalent to Query.First()).
May iterate through the elements in iteration order, ignoring the first i elements and then returning the next.
Example (Found) ¶
v := From([]T{1, 2, 3, 4, 5}).At(3)
fmt.Printf("Element at index 5: %v\n", v)
Output: Element at index 5: 4
Example (NotFound) ¶
v := From([]T{1, 2, 3, 4, 5}).At(15)
fmt.Printf("Element at index 15: %v\n", v)
Output: Element at index 15: <nil>
func (*Query) Contains ¶
Contains returns true if the collection contains an element equal to element. This operation will check each element in order for being equal to element, unless it has a more efficient way to find an element equal to element.
Example (Found) ¶
v := From([]T{1, 2, 3, 4, 5}).Contains(42)
fmt.Printf("Contains 12: %v\n", v)
Output: Contains 12: false
Example (NotFound) ¶
v := From([]T{1, 2, 3, 4, 5}).Contains(3)
fmt.Printf("Contains 6: %v\n", v)
Output: Contains 6: true
func (*Query) Every ¶
Every checks whether every element of this collection satisfies all tests. Checks every element in iteration order, and returns false if any of them make test return false, otherwise returns true.
Example (AllEven) ¶
q := From([]T{1, 3, 5, 7, 9})
v := q.Every(func(e T) bool {
return e.(int)%2 != 1
})
fmt.Printf("All numbers are even: %v\n", v)
Output: All numbers are even: false
Example (AllOdd) ¶
q := From([]T{1, 3, 5, 7, 9})
v := q.Every(func(e T) bool {
return e.(int)%2 != 0
})
fmt.Printf("All numbers are odd: %v\n", v)
Output: All numbers are odd: true
func (*Query) Expand ¶
Expand expands each element of this Query into zero or more elements.
The resulting Query runs through the elements returned by f for each element of this, in iteration order.
The returned Query is lazy, and calls f for each element of this every time it's iterated.
Example (Duplicate) ¶
q := From([]T{1, 2, 3, 4, 5})
v := q.Expand(func(e T) []T {
return []T{e, e}
})
fmt.Printf("All elements are duplicated: %v\n", v)
Output: All elements are duplicated: [1 1 2 2 3 3 4 4 5 5]
Example (Identity) ¶
q := From([]T{1, 2, 3, 4, 5})
v := q.Expand(func(e T) []T {
return []T{e}
})
fmt.Printf("All elements are identical: %v\n", v)
Output: All elements are identical: [1 2 3 4 5]
Example (Null) ¶
q := From([]T{1, 2, 3, 4, 5})
v := q.Expand(func(e T) []T {
return []T{}
})
fmt.Printf("All elements are nulled: %v\n", v)
Output: All elements are nulled: []
Example (Odd) ¶
// Remove even numbers:
q := From([]T{1, 2, 3, 4, 5})
v := q.Expand(func(e T) []T {
if e.(int)%2 == 0 {
return []T{}
}
return []T{e}
})
fmt.Printf("All elements are odd: %v\n", v)
Output: All elements are odd: [1 3 5]
func (*Query) First ¶
First returns the first element.
Example (Empty) ¶
v := From([]T{}).First()
fmt.Printf("First element: %v", v)
Output: First element: <nil>
Example (Found) ¶
v := From([]T{1, 2, 3, 4, 5}).First()
fmt.Printf("First element: %v", v)
Output: First element: 1
func (*Query) Fold ¶
Fold reduces a collection to a single value by iteratively combining each element of the collection with an existing value.
Uses v as the initial value, then iterates through the elements and updates the value with each element using the combine function.
Example (Sum) ¶
// Calculating the sum of an query:
sum := func(v, e T) interface{} {
return v.(int) + e.(int)
}
v := From([]T{1, 2, 3}).Fold(0, sum)
fmt.Printf("Folded elements to sum: %v", v)
Output: Folded elements to sum: 6
func (*Query) ForEach ¶
ForEach applies the function f to each element of this collection in iteration order.
Example (Append) ¶
v := []T{}
From([]T{1, 3, 5, 7, 9}).
ForEach(func(e T) {
v = append(v, e)
})
fmt.Printf("For each: %v", v)
Output: For each: [1 3 5 7 9]
Example (Count) ¶
v := 0
From([]T{1, 3, 5, 7, 9}).
ForEach(func(e T) {
v++
})
fmt.Printf("For each: %v", v)
Output: For each: 5
Example (Sum) ¶
v := 0
From([]T{1, 2, 3}).
ForEach(func(e T) {
v = v + e.(int)
})
fmt.Printf("For each: %v", v)
Output: For each: 6
func (*Query) IsEmpty ¶
IsEmpty returns true if there are no elements in this collection.
Example (Empty) ¶
v := From([]T{}).IsEmpty()
fmt.Printf("Empty query: %v\n", v)
Output: Empty query: true
Example (NotEmpty) ¶
v := From([]T{1}).IsEmpty()
fmt.Printf("Empty query: %v\n", v)
Output: Empty query: false
func (*Query) Join ¶
func (q *Query) Join(inner *Query, outKeySel func(e T) interface{}, innKeySel func(e T) interface{}, resultSel func(o, i interface{}) interface{}) *Query
Join correlates the elements of two collection based on matching keys.
A join refers to the operation of correlating the elements of two sources of information based on a common key. Join brings the two information sources and the keys by which they are matched together in one method call.
Join preserves the order of the elements of outer collection, and for each of these elements, the order of the matching elements of inner.
Example (Inner) ¶
v := From([]T{1, 2, 3, 4, 5}).
Join(From([]T{3, 4, 5, 6, 7}),
// Outer key selector:
func(e T) interface{} {
return e
},
// Inner key selector:
func(e T) interface{} {
return e
},
// Result selector:
func(o, i interface{}) interface{} {
return []T{o, i}
})
fmt.Printf("Inner join: %v\n", v)
Output: Inner join: [[3 3] [4 4] [5 5]]
func (*Query) Last ¶
Last returns the last element.
Example (Empty) ¶
v := From([]T{}).Last()
fmt.Printf("Last element: %v", v)
Output: Last element: <nil>
Example (Found) ¶
v := From([]T{1, 2, 3, 4, 5}).Last()
fmt.Printf("Last element: %v", v)
Output: Last element: 5
func (*Query) MapTo ¶
MapTo returns a new lazy Query with elements that are created by calling f on each element of this Query in iteration order.
This method returns a view of the mapped elements. As long as the returned Iterable is not iterated over, the supplied function f will not be invoked. The transformed elements will not be cached. Iterating multiple times over the returned Iterable will invoke the supplied function f multiple times on the same element.
Methods on the returned query are allowed to omit calling f on any element where the result isn't needed.
Example (Add) ¶
// Add a number to every slice collection element:
add := func(e T) T {
return e.(int) + 10
}
q := From([]T{1, 2, 3, 4, 5})
v := q.MapTo(add)
fmt.Printf("Map q to v: %v\n", v)
Output: Map q to v: [11 12 13 14 15]
Example (AddToEven) ¶
// Add a number to every even slice collection element:
add := func(e T) T {
if e.(int)%2 == 0 {
return e.(int) + 10
}
return e.(int)
}
q := From([]T{1, 2, 3, 4, 5})
v := q.MapTo(add)
fmt.Printf("Map q to v: %v\n", v)
Output: Map q to v: [1 12 3 14 5]
func (*Query) Reduce ¶
Reduce reduces a collection to a single value by iteratively combining elements of the collection using the provided function.
The iterable must have at least one element. If it has only one element, that element is returned.
Otherwise this method starts with the first element from the iterator, and then combines it with the remaining elements in iteration order, as if by:
v := q.First()
q.Skip(1).ForEach(func(e T) {
v = comb(v, e)
})
return v
Example (Sum) ¶
// Calculating the sum of an query:
sum := func(v, e T) interface{} {
return v.(int) + e.(int)
}
v := From([]T{1, 2, 3}).Reduce(sum)
fmt.Printf("Reduced elements to sum: %v", v)
Output: Reduced elements to sum: 6
func (*Query) Skip ¶
Skip returns an Query that provides all but the first n elements.
When the returned query is iterated, it starts iterating over this, first skipping past the initial n elements. If this has fewer than n elements, then the resulting Query is empty. After that, the remaining elements are iterated in the same order as in this query.
The n must not be negative.
Example (Empty) ¶
v := From([]T{1, 2, 3, 4, 5}).Skip(42)
fmt.Printf("Skipped 5 elements: %v", v)
Output: Skipped 5 elements: []
Example (Found) ¶
v := From([]T{1, 2, 3, 4, 5}).Skip(2)
fmt.Printf("Skipped 5 elements: %v", v)
Output: Skipped 5 elements: [3 4 5]
func (*Query) Sort ¶
Sort sorts the elements of a collection in predicate order. Elements are sorted according to a key while keeping the original order of equal elements.
Example (Decreasing) ¶
decreasing := func(e, f T) bool {
return e.(int) > f.(int)
}
q := From([]T{4, 3, 7, 2, 5, 9, 1, 6, 8})
fmt.Println(q.Sort(decreasing))
Output: [9 8 7 6 5 4 3 2 1]
Example (Increasing) ¶
increasing := func(e, f T) bool {
return e.(int) < f.(int)
}
q := From([]T{4, 3, 7, 2, 5, 9, 1, 6, 8})
fmt.Println(q.Sort(increasing))
Output: [1 2 3 4 5 6 7 8 9]
func (*Query) Take ¶
Take returns a lazy query of the n first elements of this query.
The returned Query may contain fewer than n elements, if this contains fewer than n elements.
The elements can be computed by stepping through iterator until n elements have been seen.
The n must not be negative.
Example (All) ¶
v := From([]T{1, 2, 3, 4, 5}).Take(42)
fmt.Printf("Taken elements: %v", v)
Output: Taken elements: [1 2 3 4 5]
Example (Some) ¶
v := From([]T{1, 2, 3, 4, 5}).Take(3)
fmt.Printf("Taken elements: %v", v)
Output: Taken elements: [1 2 3]
func (*Query) Where ¶
Where returns a new lazy Query with all elements that satisfy all predicate tests.
The matching elements have the same order in the returned iterable as they have in iterator.
This function returns a view of the mapped elements. As long as the returned Iterable is not iterated over, the supplied function test will not be invoked. Iterating will not cache results, and thus iterating multiple times over the returned Query may invoke the supplied function test multiple times on the same element.
Example (GreaterThan) ¶
where := func(e T) bool {
return e.(int) > 3
}
v := From([]T{1, 2, 3, 4, 5}).Where(where)
fmt.Printf("Where: %v\n", v)
Output: Where: [4 5]
Example (LessThan) ¶
where := func(e T) bool {
return e.(int) > 3
}
v := From([]T{1, 2, 3}).Where(where)
fmt.Printf("Where: %v\n", v)
Output: Where: []