cursor

package module
v0.2.2 Latest Latest
Warning

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

Go to latest
Published: Dec 1, 2023 License: AGPL-3.0 Imports: 13 Imported by: 0

README

Import cursor library to the service

$ go get gitlab.com/picnic-app/backend/libs/golang/cursor
import "gitlab.com/picnic-app/backend/libs/golang/cursor"

Model preparation

For a cursor to understand what fields of a model can be used for queries - special tag cursor has to be added to each field:

package model

import "time"

type Object struct {
    ID string `cursor:""`
    Name string
    CreatedAt time.Time `cursor:"default"`
}

Fields that are not tagged with cursor will return an error if used in a cursor. Tag value cursor:"default" tells cursor builder that this field should be used as a cursor if there’s no cursorId in request.

Default sorting

If you want for a field to be sorted explicitly by default, add sort order by the tag:

package model

import "time"

type Object struct {
    ID string `cursor:"desc"`
    Name string
    CreatedAt time.Time `cursor:"default,desc"`
}

Default sort order for fields when is not specified explicitly is ASC (ascending).

Cursor initialisation

Cursor object can be initialised in a few ways, with params or with a method chain.

Create cursor with params object:

params := &cursor.Params{
    ID:    "SUQ6MzdlOTNmYmMtNjk3Yy00NmJjLWFhNjMtZDFmMTI3MGNjYzc3",
    Dir:   1,
    Limit: 10,
}

cr, err := cursor.FromParams(Object{}, params)
if err != nil {
    panic(err)
}

Where Dir is an integer with 0 = Forward direction, 1 = Backward direction.

Create cursor with a method chain:

cr := cursor.NewDefault(Object{}).
	WithDirection(cursor.Forward).
	WithLimit(10).
	WithCursorID("Q3JlYXRlZEF0OjE2NjQxNzcyODE0NDU2NzY=")

In both cases, all parameters/arguments can be omitted for default values to be used. The only exception is the model argument which tells the cursor builder what model to use:

cr := cursor.NewDefault(Object{})
cr, err := cursor.FromParams(Object{}, &cursor.Params{})

Building SQL

Cursor SQL builder can be instantiated with the following constructor by passing cursor object and database type to it:

builder := cursor.GetBuilder(cr, cursor.Spanner)

Cursor sql should be applied to existing query at the end, since it appends ORDER BY and LIMIT directives to it.

sql := "SELECT * FROM Objects WHERE Kind = @Kind"
params := make(map[string]any)
params["Kind"] = 1

sql, params, err = cursor.GetBuilder(cr, cursor.Spanner).
    WithSQL(sql).
    WithParams(params).
    ToSQL()

// SELECT * FROM Objects WHERE Kind = @Kind AND ID < @ID ORDER BY ID LIMIT 21

When no cursor id is provided - only order by and limit will be applied to sql query:

cr = cursor.NewDefault(Object{})
sql, _, err = cr.Builder(cursor.Spanner)
	.WithSQL("SELECT * FROM Objects")
	.ToSQL()

// SELECT * FROM Objects ORDER BY CreatedAt LIMIT 21

Getting results

After executing sql query and retrieving result set, you can get a slice of result and a page info object based on a cursor data:

var out []*Object

// execute query and fetch result
...

res, page, err := cursor.GetResult(cr, out)

Resulting slice with be limited to a limit value from the cursor.

Documentation

Index

Constants

View Source
const (
	Forward direction = iota
	Backward
)

page cursor direction values

View Source
const (
	Asc sortOrder
	Desc
)

page cursor sort order values

View Source
const (
	// Spanner builder type
	Spanner sqlBuilderKind = iota + 1
)

Variables

This section is empty.

Functions

func GetEdges

func GetEdges[R any](c Cursor, in []R) ([]*Edge[R], Page, error)

GetEdges returns slice of result models wrapped with edge model

Types

type Builder

type Builder interface {
	WithSQL(sql string) Builder
	WithAlias(alias string) Builder
	WithParams(params BuilderParams) Builder
	ToSQL() (string, BuilderParams, error)
}

Builder ...

func GetBuilder

func GetBuilder(c Cursor, kind sqlBuilderKind) Builder

GetBuilder ...

type BuilderParams

type BuilderParams map[string]interface{}

BuilderParams ...

type Cursor

type Cursor interface {
	// CursorID is base64 encoded string containing field name and value to be used as a cursor
	CursorID() string
	// Limit result length with this number
	Limit() uint32
	// Direction of the search, can be either Forward or Backward
	Direction() direction
	// IsForward is true if the direction is Forward
	IsForward() bool
	// IsBackward is true if the direction is Backward
	IsBackward() bool
	// IsAsc is true if the sort order is ascending
	IsAsc() bool
	// IsPointer is true if cursor mode is Pointer
	IsPointer() bool
	// IsOffset is true if cursor mode is Offset
	IsOffset() bool
	// IsSlice is true if cursor mode is Slice
	IsSlice() bool
	// IsDesc is true if the sort order is descending
	IsDesc() bool
	// Field name in the model to be used as a cursor
	Field() string
	// Kind is a data type of cursor field
	Kind() valueType
	// Value of cursor field which will be used for search
	Value() any
	// Offset only valid for cursors with Offset mode
	Offset() uint64
	// CreateID generates new base64 cursor id
	// 	- for cursor mode Pointer - it will point to the passed object
	//  - for cursor mode Offset - it will set cursor offset to passed index
	//
	// Deprecated: it should not be used as it creates confusion on what type of parameter
	// has to be passed. In general, if you need universal way
	// to generate cursor ids - GetEdges use function instead.
	CreateID(param any) string
	// PointerID generates new base64 cursor id for pointer mode
	PointerID(obj any) string
	// OffsetID generates new base64 cursor id for offset mode
	OffsetID(index uint64) string

	// WithLimit sets result length limit
	WithLimit(limit uint32) Cursor
	// WithDirection sets search direction
	WithDirection(dir direction) Cursor
	// WithCursorID applies new cursor id to be used in a search
	WithCursorID(cursorID string) Cursor
	// WithSliceID changes mode to offset and applies passed id
	WithSliceID(cursorID string) Cursor
	// WithField sets cursor field explicitly
	WithField(field string) Cursor
	// WithSort sets cursor sorting order explicitly
	WithSort(sort sortOrder) Cursor
	// WithOffset applies offset to cursor
	WithOffset(offset uint64) Cursor
	// ToOffset force swap cursor mode and use value as offset
	ToOffset() Cursor

	// Builder helper method which returns sql builder with this cursor
	Builder(kind sqlBuilderKind) Builder
}

Cursor descriptor providing information about cursor and method to modify it

func FromParams

func FromParams(obj any, params *Params) (Cursor, error)

FromParams creates new page cursor from Params object

func NewCursor

func NewCursor(obj any, limit uint32, dir direction) (Cursor, error)

NewCursor creates new page cursor object

func NewDefault

func NewDefault(obj any) Cursor

NewDefault ...

func NewSlice

func NewSlice() Cursor

NewSlice create new slice cursor

type Edge

type Edge[R any] struct {
	// contains filtered or unexported fields
}

Edge is a cursor item container with id and node object

func (*Edge[R]) CursorID

func (e *Edge[R]) CursorID() string

CursorID get cursor id for the edge

func (*Edge[R]) Node

func (e *Edge[R]) Node() R

Node get object node

type FieldTags

type FieldTags interface {
	IsValid() bool
	IsDefault() bool
	IsOffset() bool
	SortOrder() sortOrder
}

FieldTags ...

type Page

type Page interface {
	// FirstID is id of first item on a page
	FirstID() string
	// LastID is id of last item on a page
	LastID() string
	// HasPrev indicates that there's items on a previous page
	HasPrev() bool
	// HasNext indicates that there's items on a next page
	HasNext() bool
	// Length returns length of result set
	Length() uint32

	// WithHasPrev sets HasPrev flag
	WithHasPrev(bool) Page
	// WithHasNext sets HasNext flag
	WithHasNext(bool) Page
	// WithFirstID sets first id
	WithFirstID(string) Page
	// WithLastID sets last id
	WithLastID(string) Page
	// WithLength sets length
	WithLength(uint32) Page
}

Page provides information about result page

func GetResult

func GetResult[R any](c Cursor, in []R) ([]R, Page, error)

GetResult returns slice of result models

type Params

type Params struct {
	ID    string
	Dir   int
	Limit uint32
	Field string
	Sort  int
}

Params ...

Directories

Path Synopsis
sql

Jump to

Keyboard shortcuts

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