rpc

package
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: Sep 14, 2024 License: AGPL-3.0, MIT Imports: 13 Imported by: 35

Documentation

Overview

Package rpc implements functions and structs for plugins to communicate with the main program

All exported elements prefixed with "Internal" are not meant to be used by plugins but by programs that communicate with plugins

We strongly recommend looking at the introduction to plugins in the README.md before looking at this package

Index

Constants

View Source
const (
	// OperatorEqual is the equal operator =
	OperatorEqual = 2

	// OperatorGreater is the greater than operator >
	OperatorGreater = 4

	// OperatorLessOrEqual is the less than or equal operator <=
	OperatorLessOrEqual = 8

	// OperatorLess is the less than operator <
	OperatorLess = 16

	// OperatorGreaterOrEqual is the greater than or equal operator >=
	OperatorGreaterOrEqual = 32

	// OperatorMatch is the match operator
	OperatorMatch = 64

	// OperatorLike is the like operator
	OperatorLike = 65

	// OperatorGlob is the glob operator.
	// It represents a simple pattern matching operator
	// with a UNIX syntax
	//
	// Note: A like operator is not provided because anyquery
	// converts it to a glob operator
	OperatorGlob = 66

	// OperatorRegexp is the regexp operator
	OperatorRegexp = 67

	// OperatorNotEqual is the not equal operator !=
	OperatorNotEqual = 68
	// OperatorISNOT is the IS NOT operator
	//
	// Note: will be converted to OperatorNotEqual
	OperatorIsNot = 69

	// OperatorISNOTNULL is the IS NOT NULL operator
	//
	// Note: will be converted to OperatorNotEqual with value nil
	OperatorIsNotNull = 70

	// OperatorISNULL is the IS NULL operator
	//
	// Note: will be converted to OperatorEqual with value nil
	OperatorIsNull = 71

	// OperatorIS is the IS operator
	//
	// Note: will be converted to OperatorEqual
	OperatorIs = 72

	// OperatorLimit is the LIMIT statement in a SQL query
	OperatorLimit = 73

	// OperatorOFFSET is the OFFSET statement in a SQL query
	OperatorOffset = 74
)
View Source
const MagicCookieKey = "ANYQUERY_PLUGIN"
View Source
const MagicCookieValue = "1.0.0"
View Source
const ProtocolVersion = 1

Variables

This section is empty.

Functions

This section is empty.

Types

type ColumnConstraint

type ColumnConstraint struct {
	ColumnID int
	Operator Operator
	Value    interface{}
}

func (*ColumnConstraint) GetBoolValue added in v0.1.3

func (cc *ColumnConstraint) GetBoolValue() bool

Returns the bool value of the column constraint

If the value is not a bool, it'll try to convert it to a bool If it fails or the constraints does not exist, it returns false

func (*ColumnConstraint) GetFloatValue added in v0.1.2

func (cc *ColumnConstraint) GetFloatValue() float64

Returns the float value of the column constraint

If the value is not a float, it'll try to convert it to a float If it fails or the constraints does not exist, it returns 0

func (*ColumnConstraint) GetIntValue added in v0.1.2

func (cc *ColumnConstraint) GetIntValue() int64

Returns the int value of the column constraint

If the value is not an int, it'll try to convert it to an int If it fails or the constraints does not exist, it returns 0

func (*ColumnConstraint) GetStringValue added in v0.1.2

func (cc *ColumnConstraint) GetStringValue() string

Returns the string value of the column constraint

If the value is not a string, it'll try to convert it to a string If it fails or the constraints does not exist, it returns an empty string

func (*ColumnConstraint) GetTimeValue added in v0.1.3

func (cc *ColumnConstraint) GetTimeValue() time.Time

Returns the time value of the column constraint

If the value is not a time.Time, it'll try to convert it to a time.Time If it fails or the constraints does not exist, it returns the zero value of time.Time

Supported formats are:

  • time.RFC3339
  • time.RFC822
  • time.RubyDate
  • time.UnixDate
  • time.DateTime
  • time.DateOnly
  • Unix timestamp (int64 or float64)

func (*ColumnConstraint) IsEqual added in v0.1.2

func (cc *ColumnConstraint) IsEqual() bool

Whether the column constraint is the equal operator

type ColumnType

type ColumnType int8

ColumnType is an enum that represents the type of a column

const (
	// ColumnTypeInt represents an INTEGER column
	ColumnTypeInt ColumnType = iota
	// ColumnTypeFloat represents a REAL column
	ColumnTypeFloat
	// ColumnTypeString represents a TEXT column
	ColumnTypeString
	// ColumnTypeBlob represents a BLOB column
	ColumnTypeBlob
	// ColumnTypeBool represents is an alias for ColumnTypeInt
	ColumnTypeBool = ColumnTypeInt
)

type ConnectionPool

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

ConnectionPool is a struct that holds the connections to the plugins It allows using the same executable for multiple connections

It is not intended to be used by plugins but by the main program

func NewConnectionPool

func NewConnectionPool() *ConnectionPool

NewConnectionPool creates a new connection pool

Using the zero value is not recommended and might lead to a SIGSEGV

func (*ConnectionPool) CloseConnection

func (c *ConnectionPool) CloseConnection(executableLocation string, connectionID int)

Warn the plugin that the connection will be closed, wait a few seconds and close the connection If all connections are closed, the plugin is killed

func (*ConnectionPool) NewClient

func (c *ConnectionPool) NewClient(params NewClientParams) (*InternalClient, error)

Request a new client from the connection pool. Each NewClient must be followed by a CloseConnection. If these requirements are not met, the executable will not be killed

type DatabaseSchema

type DatabaseSchema struct {
	// The columns of the table
	Columns []DatabaseSchemaColumn
	// The primary key is the index of the column where each row has a unique value
	//
	// If set to -1, it means the table does not have a primary key.
	// Therefore, the main program will generate a unique key for each row.
	// However, the table won't be able to update or delete rows.
	//
	// The primary key column type is either ColumnTypeInt or ColumnTypeString
	PrimaryKey int

	// Whether the plugin can handle an INSERT statement
	HandlesInsert bool
	// Whether the plugin can handle an UPDATE statement
	HandlesUpdate bool
	// Whether the plugin can handle a DELETE statement
	HandlesDelete bool

	// HandleOffset is a boolean that specifies whether the plugin can handle the OFFSET clause.
	// If not, the main program will skip the n offseted rows.
	HandleOffset bool

	// How many rows should anyquery buffer before sending them to the plugin
	//
	// If set to 0, the main program will send the rows one by one
	// It is used to reduce the number of API calls of plugins
	BufferInsert uint

	// How many rows should anyquery buffer before sending them to the plugin
	//
	// If set to 0, the main program will send the rows one by one
	// It is used to reduce the number of API calls of plugins
	BufferUpdate uint

	// How many rows should anyquery buffer before sending them to the plugin
	//
	// If set to 0, the main program will send the rows one by one
	// It is used to reduce the number of API calls of plugins
	BufferDelete uint
}

DatabaseSchema holds the schema of the database

It must stay the same throughout the lifetime of the plugin and for every cursor opened.

One and only field must be the primary key. If you don't have a primary key, you can generate a unique key. The primary key must be unique for each row. It is used to update and delete rows.

type DatabaseSchemaColumn

type DatabaseSchemaColumn struct {
	// The name of the column
	Name string
	// The type of the column (INTEGER, REAL, TEXT, BLOB)
	Type ColumnType
	// Whether the column is a parameter
	//
	// If a column is a parameter, it will be hidden from the user
	// in the result of a SELECT query
	// and can be passed as an argument of the table
	//
	// For example, a parameter column named account_id
	// can be used as such
	//	SELECT * FROM mytable(<account_id>)
	//	SELECT * FROM mytable WHERE account_id = <account_id>
	//
	// Arguments order is the same as the order of the columns in the schema
	IsParameter bool

	// Whether the column is required
	//
	// If a column is required, the user must provide a value for it.
	// If not, the query will fail.
	IsRequired bool

	// A description of the column
	// Not used by early versions of anyquery
	Description string
}

type DeleteArgs

type DeleteArgs struct {
	ConnectionID int
	TableIndex   int
	PrimaryKeys  []interface{}
}

type InitializeArgs

type InitializeArgs struct {
	ConnectionID int
	TableIndex   int
	Config       PluginConfig
}

InitializeArgs is a struct that holds the arguments for the Initialize method

It's necessary to define this struct because the arguments for the RPC methods are passed as a single argument

type InsertArgs

type InsertArgs struct {
	ConnectionID int
	TableIndex   int
	Rows         [][]interface{}
}

type InternalClient

type InternalClient struct {
	Client *go_plugin.Client
	Plugin InternalExchangeInterface
}

type InternalExchangeInterface

type InternalExchangeInterface interface {
	// Initialize is called when a new table is opened
	//
	// It is used by the main program to infer the schema of the tables
	Initialize(connectionID int, tableIndex int, config PluginConfig) (DatabaseSchema, error)

	// Query is a method that returns rows for a given SELECT query
	//
	// Constraints are passed as arguments for optimization purposes
	// However, the plugin is free to ignore them because
	// the main program will filter the results to match the constraints
	//
	// The first return value is a 2D slice of interface{} where each row is a slice
	// and each element in the row is an interface{} representing the value.
	// The second return value is a boolean that specifies whether the cursor is exhausted
	// The order and type of the values should match the schema of the table
	Query(connectionID int, tableIndex int, cursorIndex int, constraint QueryConstraint) ([][]interface{}, bool, error)

	// Insert is a method that inserts rows into the table
	//
	// The rows are passed as a 2D slice of interface{} where each row is a slice
	// and each element in the row is an interface{} representing the value.
	Insert(connectionID int, tableIndex int, rows [][]interface{}) error

	// Update is a method that updates rows in the table
	//
	// The rows are passed as a 2D slice of interface{} where each row is a slice
	// and each element in the row is an interface{} representing the value.
	Update(connectionID int, tableIndex int, rows [][]interface{}) error

	// Delete is a method that deletes rows from the table
	//
	// The rows are passed as an array of primary keys
	Delete(connectionID int, tableIndex int, primaryKeys []interface{}) error

	// Close is a method that is called when the connection is closed
	//
	// It is used to free resources and close connections
	Close(connectionID int) error
}

InternalExchangeInterface is an interface that defines the methods that a plugin must implement to communicate with the main program

This part should be handled by the plugin library and should not be implemented by the user

type InternalPlugin

type InternalPlugin struct {
	Impl InternalExchangeInterface
}

func (*InternalPlugin) Client

func (p *InternalPlugin) Client(b *go_plugin.MuxBroker, c *rpc.Client) (interface{}, error)

func (*InternalPlugin) Server

func (p *InternalPlugin) Server(*go_plugin.MuxBroker) (interface{}, error)

type NewClientParams

type NewClientParams struct {
	ExecutableLocation string
	Logger             hclog.Logger
	ExecutableArg      []string
	Stderr             io.Writer
}

type Operator

type Operator int8

type OrderConstraint

type OrderConstraint struct {
	ColumnID   int
	Descending bool
}

type Plugin

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

Plugin represents a plugin that can be loaded by anyquery

func NewPlugin

func NewPlugin(tables ...TableCreator) *Plugin

NewPlugin creates a new plugin

func (*Plugin) RegisterTable

func (p *Plugin) RegisterTable(tableIndex int, tableCreator TableCreator) error

RegisterTable registers a new table to the plugin

The tableIndex must be unique and match the index in the manifest

func (*Plugin) Serve

func (p *Plugin) Serve() error

Serve is a method that starts the plugin

once called, any attempt to modify the plugin will be rejected

type PluginConfig

type PluginConfig map[string]interface{}

PluginConfig is a struct that holds the configuration for the plugin

It is mostly used to specify user-defined configuration and is passed to the plugin during initialization

func (PluginConfig) GetBool added in v0.1.2

func (p PluginConfig) GetBool(key string) bool

Returns a bool value for the key in the plugin configuration

If the key does not exist or is not a bool, it returns false

func (PluginConfig) GetBoolArray added in v0.1.2

func (p PluginConfig) GetBoolArray(key string) []bool

Returns a bool array for the key in the plugin configuration

If the key does not exist or is not a bool array, it returns nil

func (PluginConfig) GetFloat added in v0.1.2

func (p PluginConfig) GetFloat(key string) float64

Returns a float value for the key in the plugin configuration

If the key does not exist or is not a float, it returns 0

func (PluginConfig) GetFloatArray added in v0.1.2

func (p PluginConfig) GetFloatArray(key string) []float64

Returns a float array for the key in the plugin configuration

If the key does not exist or is not a float array, it returns nil

func (PluginConfig) GetInt added in v0.1.2

func (p PluginConfig) GetInt(key string) int64

Returns an int value for the key in the plugin configuration

If the key does not exist or is not an int, it returns 0

func (PluginConfig) GetIntArray added in v0.1.2

func (p PluginConfig) GetIntArray(key string) []int64

Returns an int array for the key in the plugin configuration

If the key does not exist or is not an int array, it returns nil

func (PluginConfig) GetString added in v0.1.2

func (p PluginConfig) GetString(key string) string

Returns a string value for the key in the plugin configuration

If the key does not exist or is not a string, it returns an empty string

func (PluginConfig) GetStringArray added in v0.1.2

func (p PluginConfig) GetStringArray(key string) []string

Returns a string array for the key in the plugin configuration

If the key does not exist or is not a string array, it returns nil

type PluginConfigField

type PluginConfigField struct {
	Name        string
	Required    bool
	Type        string // string, int, float, bool, []string, []int, []float, []bool
	Description string
}

type PluginManifest

type PluginManifest struct {
	Name        string
	Version     string
	Author      string
	Description string
	// A list of tables that the plugin will provide
	Tables []string

	UserConfig []PluginConfigField
}

PluginManifest is a struct that holds the metadata of the plugin

It is often represented as a JSON file in the plugin directory

type PluginRPCClient

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

PluginRPCClient is a struct that holds the RPC client that will be called from the main program

func (*PluginRPCClient) Close

func (m *PluginRPCClient) Close(connectionID int) error

func (*PluginRPCClient) Delete

func (m *PluginRPCClient) Delete(connectionID int, tableIndex int, primaryKeys []interface{}) error

func (*PluginRPCClient) Initialize

func (m *PluginRPCClient) Initialize(connectionID int, tableIndex int, config PluginConfig) (DatabaseSchema, error)

func (*PluginRPCClient) Insert

func (m *PluginRPCClient) Insert(connectionID int, tableIndex int, rows [][]interface{}) error

func (*PluginRPCClient) Query

func (m *PluginRPCClient) Query(connectionID int, tableIndex int, cursorIndex int, constraint QueryConstraint) ([][]interface{}, bool, error)

func (*PluginRPCClient) Update

func (m *PluginRPCClient) Update(connectionID int, tableIndex int, rows [][]interface{}) error

type PluginRPCServer

type PluginRPCServer struct {
	Impl InternalExchangeInterface
}

PluginRPCServer is a struct that holds the RPC server that will be runned by the plugin for the main program

func (*PluginRPCServer) Close

func (m *PluginRPCServer) Close(connectionID int, resp *struct{}) error

func (*PluginRPCServer) Delete

func (m *PluginRPCServer) Delete(args *DeleteArgs, resp *struct{}) error

func (*PluginRPCServer) Initialize

func (m *PluginRPCServer) Initialize(args *InitializeArgs, resp *DatabaseSchema) error

func (*PluginRPCServer) Insert

func (m *PluginRPCServer) Insert(args *InsertArgs, resp *struct{}) error

func (*PluginRPCServer) Query

func (m *PluginRPCServer) Query(args *QueryArgs, resp *QueryReturn) error

func (*PluginRPCServer) Update

func (m *PluginRPCServer) Update(args *UpdateArgs, resp *struct{}) error

type QueryArgs

type QueryArgs struct {
	ConnectionID int
	TableIndex   int
	CursorIndex  int
	Constraint   QueryConstraint
}

QueryArgs is a struct that holds the arguments for the Query method (see InitializeArgs)

type QueryConstraint

type QueryConstraint struct {
	// The constraints for each column (can be skipped and SQLite will handle it)
	Columns []ColumnConstraint

	// The maximum number of rows to return
	//
	// If set to -1, it means no limit
	Limit int

	// The number of rows to skip
	//
	// If set to -1, it means no offset
	Offset int

	// The order by constraints (can be skipped and SQLite will handle it)
	OrderBy []OrderConstraint
}

QueryConstraint is a struct that holds the constraints for a SELECT query

It specifies the WHERE conditions in the Columns field, the LIMIT and OFFSET in the Limit and Offset fields, and the ORDER BY clause in the OrderBy field

func (QueryConstraint) GetColumnConstraint added in v0.1.2

func (qc QueryConstraint) GetColumnConstraint(columnID int) *ColumnConstraint

Returns the column constraint for the given column at the index columnID

If the column does not exist, it returns nil

type QueryReturn

type QueryReturn struct {
	Rows       [][]interface{}
	NoMoreRows bool
}

type ReaderInterface

type ReaderInterface interface {

	// Query is a method that returns rows for a given SELECT query
	//
	// Constraints are passed as arguments for optimization purposes
	// However, the plugin is free to ignore them because
	// the main program will filter the results to match the constraints
	//
	// The first return value is a 2D slice of interface{} where each row is a slice
	// and each element in the row is an interface{} representing the value.
	// The second return value is a boolean that specifies whether the cursor is exhausted
	// The order and type of the values should match the schema of the table
	Query(constraint QueryConstraint) ([][]interface{}, bool, error)
}

ReaderInterface is an interface that must be implemented by the plugin

It maps the methods required by anyquery to work

type Table

type Table interface {
	// CreateReader must return a new instance of a table reader
	// A table can have several concurrent readers for better performance
	CreateReader() ReaderInterface

	// Insert is called when the main program wants to insert rows
	//
	// The rows are passed as a 2D slice of interface{} where each row is a slice
	// and each element in the row is an interface{} representing the value.
	//
	// interface{} can be an int, string, int64, float64, []byte or nil
	Insert(rows [][]interface{}) error

	// Update is called when the main program wants to update rows
	//
	// The rows are passed as a 2D slice of interface{} where each row is a slice
	// and each element in the row is an interface{} representing the value.
	//
	// The primary key is at the index specified in the schema and is also at the first index of the row.
	// It is used to update the value of the primary key in the row. The first value is the former value
	// and the second value is the new value.
	//
	// interface{} can be an int, string, int64, float64, []byte or nil
	Update(rows [][]interface{}) error

	// Delete is called when the main program wants to delete rows
	//
	// The primary keys are passed as an array of interface{}
	Delete(primaryKeys []interface{}) error

	// Close is called when the connection is closed
	//
	// It is used to free resources and close connections
	Close() error
}

Represents a table in the plugin

If your table doesn't support insert, update or delete, you should specify it in the schema and the according methods will not be called. They can return an error or nil

type TableCreator

type TableCreator func(args TableCreatorArgs) (Table, *DatabaseSchema, error)

TableCreator is a function that creates a new table interface and returns the schema of the table

type TableCreatorArgs

type TableCreatorArgs struct {
	// UserConfig is the configuration passed by the user
	// during the configuration of the plugin profile
	UserConfig PluginConfig

	// TableIndex is the index of the table in the manifest (0-based)
	TableIndex int

	// ConnectionID is the index of the connection.
	// It is used to identify the connection in the plugin and can change between restarts
	ConnectionID int
}

Args passed to the TableCreator function

Implementation details: args are passed as a struct so that if we add more arguments in the future, old plugins will still work

type UpdateArgs

type UpdateArgs struct {
	ConnectionID int
	TableIndex   int
	Rows         [][]interface{}
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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