queryplanner

package module
v0.1.18 Latest Latest
Warning

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

Go to latest
Published: Jan 28, 2026 License: BSD-3-Clause Imports: 6 Imported by: 0

README

QueryPlanner

A Golang library for planning queries in a structured order

Table of Contents

1. Description

QueryPlanner is a generic library that aims to provide a framework for structuring queries that might need to reach different services or go through different steps to enrich a response. The library provides a way of describing the query's steps(IndexProviders/FieldProviders) and it's dependencies.

2. Technology Stack

Stack Version
Golang v1.21
golangci-lint v1.46.2

3. Getting Started

  • Prerequisites
    • Any Golang programming language version installed, preferred 1.21 or later.
  • Install
    go get -u github.com/arquivei/queryplanner
    
  • Configuration Setup
    go mod vendor
    go mod tidy
    
  • Usage
    • Import the package

      import (
          "github.com/arquivei/queryplanner"
      )
      
    • Define a request struct that implements queryplanner.Request interface

        type Request struct {
        	Fields []string
        }
      
        func (r *Request) GetRequestedFields() []string {
        	return r.Fields
        }
      
      • This struct will be passed to all your providers and can be used to pass information such as pagination and filters.
    • Define a struct to be filled by your providers

      type Person struct {
      	Name      *string 
      	FirstName *string
      }
      
    • Define a provider that implements the queryplanner.IndexProvider interface

      type indexProvider struct {}
      
      func (p *indexProvider) Provides() []queryplanner.Index {
          return []queryplanner.Index{
      		{
      			Name: "Name",
      			Clear: func(d queryplanner.Document) {
      				doc, _ := d.(*Person)
      				doc.Name = nil
      			},
      	    },
          }
      }
      
      func (p *indexProvider) Execute(ctx context.Context, request queryplanner.Request, fields []string) (*queryplanner.Payload, error) {
          return &queryplanner.Payload{
      		Documents: []queryplanner.Document{
      		    &Person{
      		        Name: "Maria Joana",
      		    },
      		},
          }, nil
      }
      
      • This is the first provider to be executed and it has the responsability of setting the payload documents that will be modified by the other providers.
    • Define a provider that implements the queryplanner.FieldProvider interface

      type fieldProvider struct {}
      
      func (p *fieldProvider) Provides() []queryplanner.Field {
          return []queryplanner.Field{
      		{
      			Name: "Name",
      			Fill: func(index int, ec queryplanner.ExecutionContext) error {
      			    doc := ec.Payload.Documents[i].(*Person)
      			    doc.FirstName = strings.Split(doc.Name, " ")[0]
      			    return nil
      			},
      			Clear: func(d queryplanner.Document) {
      				doc, _ := d.(*Person)
      				doc.Name = nil
      			},
      	    },
          }
      }
      
      func (p *fieldProvider) DependsOn() []queryplanner.FieldName {
      	return []queryplanner.FieldName{
      		"Name",
      	}
      }
      
      • The field provider must say what fields it depends on to be used and what fields it provides.
    • Finally you can create your queryplanner and make requests to it:

      import (
          "github.com/arquivei/queryplanner"
      )
      
      func main() {
          // Create the planner
          planner, err := queryplanner.NewQueryPlanner(indexProvider{}, fieldProvider{})
      	if err != nil {
      		panic(err)
      	}
      
      	// Make requests to it
      	payload, err := planner.Plan(Request{ 
      	    Fields: []string{"Name", "FirstName"}
      	}).Execute()
      }
      
  • Examples

    For more in-depth examples of how to use the library, check the examples folder.

4. Changelog

  • queryplanner 0.1.0 (May 31, 2022)

    • [New] Documents: Code of Conduct, Contributing, License and Readme.
    • [New] Setting github's workflow with golangci-lint
    • [New] Decoupling this package from Arquivei's API projects.

5. Collaborators

6. Contributing

Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.

7. Versioning

We use Semantic Versioning for versioning. For the versions available, see the tags on this repository.

8. License

This project is licensed under the BSD 3-Clause - see the LICENSE.md file for details.

9. Contact Information

All contact may be doing by marcos.filho@arquivei.com.br

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Cache

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

Cache caches the result of a function.

func (*Cache) GetOrLoad

func (c *Cache) GetOrLoad(key interface{}, loader CacheEntryLoader) (interface{}, error)

GetOrLoad tries to retrieve an existing element from the cache by an indexed `key` . If there is already an entry for (CacheEntry) the key, the cached content is returned. If there is not a cached value, then `loader` (CacheEntryLeader) is executed and its results are cached using the provided `key` as index.

type CacheEntry

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

CacheEntry is the stored element in Cache.

type CacheEntryLoader

type CacheEntryLoader func() (interface{}, error)

CacheEntryLoader is a function that caches the result of the first call of function.

type Document

type Document interface{}

Document is an interface that represents a generic data structure.

type ExecutionContext

type ExecutionContext struct {
	Context context.Context
	Request Request

	Payload *Payload
	// contains filtered or unexported fields
}

ExecutionContext is used during the filling process. It stores essential data structures to executing the enrichment processes.

func (*ExecutionContext) Cache

func (e *ExecutionContext) Cache() *Cache

Cache instatiates a new Cache.

type Field

type Field struct {
	Name  FieldName
	Fill  func(int, ExecutionContext) error
	Clear func(Document)
}

Field represents a valid field. It has a name and functions for filling and cleaning itself.

type FieldName

type FieldName string

FieldName is a string representing a valid field.

type FieldProvider

type FieldProvider interface {
	Provides() []Field
	DependsOn() []FieldName
}

FieldProvider is able to load an existing set of []Document with certain fields. The `Provides()` returns a list of Field's, which in turn contains methods to filling and cleaning a Document.

type Index

type Index struct {
	Name  FieldName
	Clear func(Document)
}

Index represents a valid index. It has a name and functions for cleaning itself.

type IndexProvider

type IndexProvider interface {
	Execute(ctx context.Context, request Request, fields []string) (*Payload, error)
	Provides() []Index
}

IndexProvider is similar to FieldProvider in some aspects: it also provides specifically defined fields and encapsulates the mechanics of retrieving and populating them. However, the IndexProvider should not depend on anyone else, as FieldProvider does. Also, an IndexProvider has an additional responsibility: to create the initial base of documents (encapsulated inside Payload) to be enriched by the FieldProviders.

type Payload

type Payload struct {
	Documents  []Document
	CustomData interface{}
}

Payload stores the slice of documents and also supports an arbitrary data to be used when necessary.

type Plan

type Plan interface {
	Execute(context.Context) (*Payload, error)
}

Plan is the product of the QueryPlanner. It can be executed, returning a Payload with the enriched Document and CustomData.

type QueryPlanner

type QueryPlanner interface {
	NewPlan(Request) Plan
}

QueryPlanner is an interface that creates a Plan.

func NewQueryPlanner

func NewQueryPlanner(indexProvider IndexProvider, providers ...FieldProvider) (QueryPlanner, error)

NewQueryPlanner returns a new query planner unsing @providers.

type Request

type Request interface {
	GetRequestedFields() []string
}

Request is an interface for getting the requested fields of a Request and also for retrieving an inner Request structure as well.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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