workshop

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 4, 2023 License: Apache-2.0 Imports: 2 Imported by: 0

README

workshop

Go Report Card Documentation

The Build-A-Where Workshop is a tiny package that helps you write conditional clauses for your database queries.

The inspiration for this package is all of the gems that one might find out there in the Ruby world for database-agnostic query building.

Huh?

For example, instead of exposing a bunch of PostgreSQL-specific nonsense like this:

db.WithContext(ctx).First("name = ? AND age = ?", woozle.Name, woozle.Age)

You might do something like this:


myTransformer := func(groups []workshop.Group) []any {
  // do stuff that converts the groups of clauses to the arguments one would
  // use in your database's prepare statements, returned as an array
}

// Assuming that both workshop and workshop/op have been imported ...
db.WithContext(ctx).First(
  workshop.
    Where("name", op.Equal, woozle.Name).
    And("age", op.Equal, woozle.Age).
    Transform(myTransformer)...,
)

Installation

go get -u codeberg.org/build-a-where/workshop

Core Concepts

Condition

A Condition is a single aspect of a typical WHERE-type clause. It is generally a field name, an operator, and a value.

Group

A Group is a list of Conditions. Conceptually, there is a natural AND between each of them, and there is a natural OR between any two groups.

Filter

A Filter is a builder that allows one to programmatically create full clauses. While you're welcome to create your own raw *workshop.Filter reference, the best way to create a filter is with baw.Where().

Transformer

A transformer is a function that takes a collection of Groups and spits out a collection of any that represents the arguments one would use to set up a prepared statement in one's database of choice.

You largely shouldn't have to write your own transformer, but would most typically use a transformer provided by the build-a-where community.

Full Usage Example

package main

import (
	"fmt"
	"strings"

	"codeberg.org/build-a-where/workshop"
	"codeberg.org/build-a-where/workshop/op"
)

func main() {
	query := workshop.
		Where("id", op.Equal, 1).
		And("name", op.Like, "John%").
		Or("age", op.GreaterThan, 18).
		And("age", op.LessThan, 30).
		Or("age", op.In, []int{1, 2, 3}).
		And("age", op.NotIn, []int{4, 5, 6})

	final := make([]string, 0)

	for _, item := range query.Transform(transformer) {
		final = append(final, fmt.Sprintf("%v", item))
	}

	fmt.Println(strings.Join(final, ", "))
}

func transformer(groups []workshop.Group) []any {
	output := make([]any, 0)
	og := make([]string, 0)

	values := make([]any, 0)

	for _, group := range groups {
		g := make([]string, 0)

		for _, condition := range group {
			g = append(g, fmt.Sprintf("%s %s ?", condition.Column, renderOp(condition.Op)))
			values = append(values, condition.Value)
		}

		og = append(og, fmt.Sprintf("(%s)", strings.Join(g, " AND ")))
	}

	output = append(output, fmt.Sprintf(`"%s"`, strings.Join(og, " OR ")))
	output = append(output, values...)

	return output
}

func renderOp(o op.Op) string {
	switch o {
	case op.Equal:
		return "="
	case op.NotEqual:
		return "<>"
	case op.GreaterThan:
		return ">"
	case op.LessThan:
		return "<"
	case op.GreaterOrEqual:
		return ">="
	case op.LessOrEqual:
		return "<="
	case op.Like:
		return "LIKE"
	case op.In:
		return "IN"
	case op.NotIn:
		return "NOT IN"
	case op.Null:
		return "IS NULL"
	case op.NotNull:
		return "IS NOT NULL"
	default:
		return ""
	}
}

History

  • v1.0.0 - The workshop's open!

Documentation

Overview

package workshop provides a simple interface to build a where query for any database in a simple filter-style manner.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Condition

type Condition struct {
	Column string
	Op     op.Op
	Value  interface{}
}

Condition is a struct that holds a single condition for a query. It is made of a column, an operator and a value. For some operators, the value may be superfluous.

type Filter

type Filter struct {
	// contains filtered or unexported fields
}

Filter is a struct that holds the conditions for a query. It can be used to build a query for any database. It is thread-safe. It uses the builder pattern.

func Where

func Where(column string, o op.Op, value interface{}) *Filter

Where creates a new Filter and adds a condition to it.

func (*Filter) And

func (f *Filter) And(column string, o op.Op, value interface{}) *Filter

And adds a condition to the filter. It is thread-safe. It uses the builder pattern. It returns the Filter itself. It always adds the condition to the last group. If there is no group, it creates one.

func (*Filter) Or

func (f *Filter) Or(column string, o op.Op, value interface{}) *Filter

Or adds a condition to the filter. It is thread-safe. It uses the builder pattern. It returns the Filter itself. It always adds the condition to a new group.

func (*Filter) Transform

func (f *Filter) Transform(t Transformer) []any

Transform applies the given Transformer to the filter's groups and returns the final query as per the transformer's implementation. It is thread-safe.

type Group

type Group []Condition

Group is a collection of conditions that have an AND relationship.

type Transformer

type Transformer func([]Group) []any

Transformer is a function that receives groups of conditions and returns the query and its values as they may be used in a prepared statement.

Directories

Path Synopsis
package op defines the operators used in the where clause of a query.
package op defines the operators used in the where clause of a query.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL