Skip to content

Commit

Permalink
feat(query): go 1.23 iterator support
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasmalkmus committed Aug 10, 2024
1 parent 22adcbe commit 19e1d8a
Show file tree
Hide file tree
Showing 12 changed files with 218 additions and 54 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test_examples.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ jobs:
if: matrix.setup
run: ${{ matrix.setup }}
- name: Run example
run: go run ./examples/${{ matrix.example }}/main.go
run: go run ./examples/${{ matrix.example }}
- name: Verify example
if: matrix.verify
run: ${{ matrix.verify }}
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
[![Latest Release][release_badge]][release]
[![License][license_badge]][license]


[Axiom](https://axiom.co) unlocks observability at any scale.

- **Ingest with ease, store without limits:** Axiom's next-generation datastore
Expand Down
15 changes: 0 additions & 15 deletions axiom/query/result.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package query

import (
"context"
"encoding/json"
"time"

"github.com/axiomhq/axiom-go/axiom/query/iter"
)

// Result is the result of an APL query.
Expand Down Expand Up @@ -46,11 +43,6 @@ type Table struct {
Columns []Column `json:"columns"`
}

// Rows returns an iterator over the rows build from the columns the table.
func (t Table) Rows() iter.Iter[Row] {
return Rows(t.Columns)
}

// Source that was consulted in order to create a [Table].
type Source struct {
// Name of the source.
Expand Down Expand Up @@ -99,13 +91,6 @@ type Buckets struct {
// Column in a [Table] containing the raw values of a [Field].
type Column []any

// Values returns an iterator over the values of the column.
func (c Column) Values() iter.Iter[any] {
return iter.Slice(c, func(_ context.Context, v any) (any, error) {
return v, nil
})
}

// Status of an APL query [Result].
type Status struct {
// MinCursor is the id of the oldest row, as seen server side. May be lower
Expand Down
21 changes: 21 additions & 0 deletions axiom/query/result_iter_go122.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//go:build !go1.23

package query

import (
"context"

"github.com/axiomhq/axiom-go/axiom/query/iter"
)

// Rows returns an iterator over the rows build from the columns the table.
func (t Table) Rows() iter.Iter[Row] {
return Rows(t.Columns)
}

// Values returns an iterator over the values of the column.
func (c Column) Values() iter.Iter[any] {
return iter.Slice(c, func(_ context.Context, v any) (any, error) {
return v, nil
})
}
21 changes: 21 additions & 0 deletions axiom/query/result_iter_go123.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//go:build go1.23

package query

import "iter"

// Rows returns an iterator over the rows build from the columns the table.
func (t Table) Rows() iter.Seq[Row] {
return Rows(t.Columns)
}

// Values returns an iterator over the values of the column.
func (c Column) Values() iter.Seq[any] {
return func(yield func(any) bool) {
for _, v := range c {
if !yield(v) {
return
}
}
}
}
37 changes: 0 additions & 37 deletions axiom/query/row.go
Original file line number Diff line number Diff line change
@@ -1,41 +1,4 @@
package query

import (
"context"

"github.com/axiomhq/axiom-go/axiom/query/iter"
)

// Row represents a single row of a tabular query [Result].
type Row []any

// Values returns an iterator over the values of the row.
func (r Row) Values() iter.Iter[any] {
return iter.Slice(r, func(_ context.Context, v any) (any, error) {
return v, nil
})
}

// Rows returns an iterator over the rows build from the columns of a tabular
// query [Result].
func Rows(columns []Column) iter.Iter[Row] {
// Return an empty iterator if there are no columns or column values.
if len(columns) == 0 || len(columns[0]) == 0 {
return func(context.Context) (Row, error) {
return nil, iter.Done
}
}

return iter.Range(0, len(columns[0]), func(_ context.Context, idx int) (Row, error) {
if idx >= len(columns[0]) {
return nil, iter.Done
}

row := make(Row, len(columns))
for columnIdx, column := range columns {
row[columnIdx] = column[idx]
}

return row, nil
})
}
2 changes: 2 additions & 0 deletions axiom/query/row_test.go → axiom/query/row_go122_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build !go1.23

package query_test

import (
Expand Down
45 changes: 45 additions & 0 deletions axiom/query/row_go123_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//go:build go1.23

package query_test

import (
"fmt"
"strings"

"github.com/axiomhq/axiom-go/axiom/query"
)

func ExampleRows() {
columns := []query.Column{
[]any{
"2020-11-19T11:06:31.569475746Z",
"2020-11-19T11:06:31.569479846Z",
},
[]any{
"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)",
"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)",
},
[]any{
"93.180.71.3",
"93.180.71.3",
},
[]any{
"GET /downloads/product_1 HTTP/1.1",
"GET /downloads/product_1 HTTP/1.1",
},
[]any{
304,
304,
},
}

var buf strings.Builder
for row := range query.Rows(columns) {
_, _ = fmt.Fprintln(&buf, row)
}

// Output:
// [2020-11-19T11:06:31.569475746Z Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21) 93.180.71.3 GET /downloads/product_1 HTTP/1.1 304]
// [2020-11-19T11:06:31.569479846Z Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21) 93.180.71.3 GET /downloads/product_1 HTTP/1.1 304]
fmt.Print(buf.String())
}
40 changes: 40 additions & 0 deletions axiom/query/row_iter_go122.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//go:build !go1.23

package query

import (
"context"

"github.com/axiomhq/axiom-go/axiom/query/iter"
)

// Values returns an iterator over the values of the row.
func (r Row) Values() iter.Iter[any] {
return iter.Slice(r, func(_ context.Context, v any) (any, error) {
return v, nil
})
}

// Rows returns an iterator over the rows build from the columns of a tabular
// query [Result].
func Rows(columns []Column) iter.Iter[Row] {
// Return an empty iterator if there are no columns or column values.
if len(columns) == 0 || len(columns[0]) == 0 {
return func(context.Context) (Row, error) {
return nil, iter.Done
}
}

return iter.Range(0, len(columns[0]), func(_ context.Context, idx int) (Row, error) {
if idx >= len(columns[0]) {
return nil, iter.Done
}

row := make(Row, len(columns))
for columnIdx, column := range columns {
row[columnIdx] = column[idx]
}

return row, nil
})
}
39 changes: 39 additions & 0 deletions axiom/query/row_iter_go123.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//go:build go1.23

package query

import (
"iter"
)

// Values returns an iterator over the values of the row.
func (r Row) Values() iter.Seq[any] {
return func(yield func(any) bool) {
for _, v := range r {
if !yield(v) {
return
}
}
}
}

// Rows returns an iterator over the rows build from the columns of a tabular
// query [Result].
func Rows(columns []Column) iter.Seq[Row] {
// Return an empty iterator if there are no columns or column values.
if len(columns) == 0 || len(columns[0]) == 0 {
return func(func(Row) bool) {}
}

return func(yield func(Row) bool) {
for i := range columns[0] {
row := make(Row, len(columns))
for j, column := range columns {
row[j] = column[i]
}
if !yield(row) {
return
}
}
}
}
2 changes: 2 additions & 0 deletions examples/query/main.go → examples/query/main_go122.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build !go1.23

// The purpose of this example is to show how to query a dataset using the Axiom
// Processing Language (APL).
package main
Expand Down
47 changes: 47 additions & 0 deletions examples/query/main_go123.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//go:build go1.23

// The purpose of this example is to show how to query a dataset using the Axiom
// Processing Language (APL).
package main

import (
"context"
"fmt"
"log"
"os"

"github.com/axiomhq/axiom-go/axiom"
)

func main() {
// Export "AXIOM_DATASET" in addition to the required environment variables.

dataset := os.Getenv("AXIOM_DATASET")
if dataset == "" {
log.Fatal("AXIOM_DATASET is required")
}

ctx := context.Background()

// 1. Initialize the Axiom API client.
client, err := axiom.NewClient()
if err != nil {
log.Fatal(err)
}

// 2. Query all events using APL ⚡
apl := fmt.Sprintf("['%s']", dataset) // E.g. ['test']
res, err := client.Query(ctx, apl)
if err != nil {
log.Fatal(err)
} else if res.Status.RowsMatched == 0 {
log.Fatal("No matches found")
}

// 3. Print the queried results by creating a iterator for the rows from the
// tabular query result (as it is organized in columns) and iterating over
// the rows.
for row := range res.Tables[0].Rows() {
_, _ = fmt.Println(row)
}
}

0 comments on commit 19e1d8a

Please sign in to comment.