An open API service indexing awesome lists of open source software.

https://github.com/miyamo2/filtgen

generate an iterator by go generate that can filter by field values of the item.
https://github.com/miyamo2/filtgen

cli code-generation codegen filter filtering go gogenerate golang iterator iterator-library rangefunc

Last synced: 16 days ago
JSON representation

generate an iterator by go generate that can filter by field values of the item.

Awesome Lists containing this project

README

        

# filtgen

[![Go Reference](https://pkg.go.dev/badge/github.com/miyamo2/filtgen.svg)](https://pkg.go.dev/github.com/miyamo2/filtgen)
[![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/miyamo2/filtgen)](https://img.shields.io/github/go-mod/go-version/miyamo2/filtgen)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/miyamo2/filtgen)](https://img.shields.io/github/v/release/miyamo2/filtgen)
[![ci](https://github.com/miyamo2/filtgen/actions/workflows/ci.yaml/badge.svg)](https://github.com/miyamo2/filtgen/actions/workflows/ci.yaml)
[![Go Report Card](https://goreportcard.com/badge/github.com/miyamo2/filtgen)](https://goreportcard.com/report/github.com/miyamo2/filtgen)
[![GitHub License](https://img.shields.io/github/license/miyamo2/filtgen?&color=blue)](https://img.shields.io/github/license/miyamo2/filtgen?&color=blue)

CLI tool for generating iterators that selects items by their field values.

## Quick Start

### Install

```sh
go install github.com/miyamo2/filtgen@latest
```

### Usage

#### Step 1: Tag your struct with the `filtgen`

```go
//go:generate filtgen generate -s $GOFILE
package main

import (
"time"
)

type Foo struct {
StringField string `filtgen:"*"`
IntField int `filtgen:"*"`
BoolField bool `filtgen:"*"`
TimeField time.Time `filtgen:"*"`
ErrorField error `filtgen:"*"`
}
```

#### Step 2: Run `filtgen generate`

##### Run with `go generate`

```sh
go generate ./...
```

##### Run with `filtgen` command

```sh
filtgen generate -s your_struct.go
```

#### Step 3: Use generated iterator

```go
errSomething := errors.New("something")

s := []Foo{
{StringField: "a", IntField: 1, BoolField: true, TimeField: time.Now()},
{StringField: "b", IntField: 2, BoolField: false, TimeField: time.Now(), ErrorField: errSomething},
{StringField: "c", IntField: 3, BoolField: true, TimeField: time.Now().Add(-(time.Hour * 2))},
}

for i, v := range FooSlice(s).StringFieldGe("a") {
fmt.Printf("%d: %s\n", i, v.StringField)
}
// Output: 0: a
// 1: b
// 2: c

for i, v := range FooSlice(s).IntFieldGt(1) {
fmt.Printf("%d: %s\n", i, v.StringField)
}
// Output: 1: b
// 2: c

for i, v := range FooSlice(s).BoolFieldEq(true) {
fmt.Printf("%d: %s\n", i, v.StringField)
}
// Output: 0: a
// 2: c

for i, v := range FooSlice(s).TimeFieldMatches(func(t time.Time) bool { return t.Before(time.Now()) }) {
fmt.Printf("%d: %s\n", i, v.StringField)
}
// Output: 2: c

for i, v := range FooSlice(s).ErrorFieldIs(errSomething) {
fmt.Printf("%d: %s\n", i, v.StringField)
}
// Output: 1: b

// with method chaining
for i, v := range FooSlice(s).IntFieldGt(1).StringFieldNe("c") {
fmt.Printf("%d: %s\n", i, v.StringField)
}
// Output: 1: b
```

For the actual generated code, see the [example](https://github.com/miyamo2/filtgen/tree/main/example).

## What codes to be generated?

### Types

`filtgen` generates the following defined-types.

- `XxxSlice`(`[]T`)

- `XxxMap[K]`(`map[K compareble]T`)

- `XxxSeq[T]`(`iter.Seq[T]`)

- `XxxSeq2[T]`(`iter.Seq2[T, U]`)

Type name is determined by the struct name; e.g. `User` -> `UserSlice`.

To use the generated methods, cast must be performed.
```go
s := []User{
{Name: "Alice"},
{Name: "Bob"},
}
for i, v := range UserSlice(s).NameEq("Alice") {
fmt.Printf("%d: %s\n", i, v.Name)
}
```

### Methods

Following methods are generated by `filtgen`.

- [`XxxEq`](https://github.com/miyamo2/filtgen/tree/main/README.md#xxxeq)
- [`XxxNe`](https://github.com/miyamo2/filtgen/tree/main/README.md#xxxne)
- [`XxxGt`](https://github.com/miyamo2/filtgen/tree/main/README.md#xxxgt)
- [`XxxLt`](https://github.com/miyamo2/filtgen/tree/main/README.md#xxxlt)
- [`XxxGe`](https://github.com/miyamo2/filtgen/tree/main/README.md#xxxge)
- [`XxxLe`](https://github.com/miyamo2/filtgen/tree/main/README.md#xxxle)
- [`XxxMatches`](https://github.com/miyamo2/filtgen/tree/main/README.md#xxxmatches)
- [`XxxIs`](https://github.com/miyamo2/filtgen/tree/main/README.md#xxxis)
- [`XxxIsnt`](https://github.com/miyamo2/filtgen/tree/main/README.md#xxxisnt)

Method name is determined by the field name; e.g. `Name` -> `NameEq`.

#### `XxxEq`

Selects iterator items whose field values are equal to the specified value.

```go
type User struct {
Name string `filtgen:"eq"`
}
```

```go
for i, v := range UserSlice(s).NameEq("Alice") {
fmt.Printf("%d: %s\n", i, v.Name)
}
```

#### `XxxNe`

Selects iterator items whose field values are not equal to the specified value.

```go
type User struct {
Name string `filtgen:"ne"`
}
```

```go
for i, v := range UserSlice(s).NameNe("Alice") {
fmt.Printf("%d: %s\n", i, v.Name)
}
```

#### `XxxGt`

Selects iterator items whose field values are greater than the specified value.

```go
type User struct {
Name string `filtgen:"gt"`
}
```

```go
for i, v := range UserSlice(s).NameGt("Alice") {
fmt.Printf("%d: %s\n", i, v.Name)
}
```

#### `XxxLt`

Selects iterator items whose field values are less than the specified value.

```go
type User struct {
Name string `filtgen:"lt"`
}
```

```go
for i, v := range UserSlice(s).NameLt("Alice") {
fmt.Printf("%d: %s\n", i, v.Name)
}
```

#### `XxxGe`

Selects iterator items whose field values are greater than or equal to the specified value.

```go
type User struct {
Name string `filtgen:"ge"`
}
```

```go
for i, v := range UserSlice(s).NameGe("Alice") {
fmt.Printf("%d: %s\n", i, v.Name)
}
```

#### `XxxLe`

Selects iterator items whose field values are less than or equal to the specified value.

```go
type User struct {
Name string `filtgen:"le"`
}
```

```go
for i, v := range UserSlice(s).NameLe("Alice") {
fmt.Printf("%d: %s\n", i, v.Name)
}
```

#### `XxxMatches`

Selects iterator items whose field values match the specified function.

```go
type User struct {
Name string `filtgen:"matches"`
}
```

```go
for i, v := range UserSlice(s).NameMatches(func(s string) bool { return strings.HasPrefix(s, "A") }) {
fmt.Printf("%d: %s\n", i, v.Name)
}
```

#### `XxxIs`

Selects iterator items whose field values are equal to the specified `error`.
Equivalence is determined by `errors.Is`.

```go
type Transaction struct {
ID string `filtgen:"eq"`
Err error `filtgen:"is"`
}
```

```go
for i, v := range TransactionSlice(s).ErrIs(fmt.Errorf("something")) {
fmt.Printf("%d: %s\n", i, v.ID)
}
```

#### `XxxIsnt`

Selects iterator items whose field values are not equal to the specified `error`.
Equivalence is determined by `errors.Is`.

```go
type Transaction struct {
ID string `filtgen:"eq"`
Err error `filtgen:"isnt"`
}
```

```go
for i, v := range TransactionSlice(s).ErrIsnt(fmt.Errorf("something")) {
fmt.Printf("%d: %s\n", i, v.ID)
}
```

#### List of compatible filters by type

| Type\Filter | `XxxEq` | `XxxNe` | `XxxGt` | `XxxLt` | `XxxGe` | `XxxLe` | `XxxMatches` | `XxxIs` | `XxxIsnt` |
|--------------|---------|---------|---------|---------|---------|---------|--------------|---------|-----------|
| `string` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| `int` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| `int8` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| `int16` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| `int32` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| `int64` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| `uint` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| `uint8` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| `uint16` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| `uint32` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| `uint64` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| `float32` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| `float64` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| `complex64` | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| `complex128` | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| `byte` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| `rune` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| `error` | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ |
| `bool` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| other-types | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |

### `filtgen` tags

The following values can be set in the `filtgen` tag.
If you want to set multiple values, separate them with `,`.

```go
type A struct {
StringField string `filtgen:"eq,ne"`
}
```

| Value | Description |
|-----------|---------------------------------------------------------------------|
| `*` | Generate all methods supported according to the type of that field. |
| `eq` | Generate `XxxEq` methods. |
| `ne` | Generate `XxxNe` methods. |
| `gt` | Generate `XxxGt` methods. |
| `lt` | Generate `XxxLt` methods. |
| `ge` | Generate `XxxGe` methods. |
| `le` | Generate `XxxLe` methods. |
| `matches` | Generate `XxxMatches` methods. |
| `is` | Generate `XxxIs` methods. |
| `isnt` | Generate `XxxIsnt` methods. |

## For Contributors

Feel free to open a PR or an Issue.
However, you must promise to follow our [Code of Conduct](https://github.com/miyamo2/filtgen/blob/main/CODE_OF_CONDUCT.md).

### Tasks

We recommend that this section be run with [`xc`](https://github.com/joerdav/xc).

#### setup:deps

Install `golangci-lint`.

```sh
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
```

#### lint

```sh
golangci-lint run --fix
```

## License

**filtgen** released under the [MIT License](https://github.com/miyamo2/filtgen/blob/main/LICENSE)