sqlp

package module
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Sep 29, 2020 License: Unlicense Imports: 4 Imported by: 1

README

Overview

SQL Parse: simple parser for rewriting fragments of foreign code embedded in SQL queries, such as parameter placeholders: $1 or :ident, or code encased in delimiters: () [] {}. Anything the parser doesn't recognize is preserved as text.

See the full documentation at https://godoc.org/github.com/mitranim/sqlp.

Changelog

0.1.1

Replaced []rune with string. When parsing, we treat the input string as UTF-8, decoding on the fly.

0.1.0

First tagged release.

License

https://unlicense.org

Misc

I'm receptive to suggestions. If this library almost satisfies you but needs changes, open an issue or chat me up. Contacts: https://mitranim.com/#contacts

Documentation

Overview

Parser for rewriting fragments of foreign code embedded in SQL queries, such as parameter placeholders: `$1` or `:ident`, or code encased in delimiters: `()` `[]` `{}`. It supports the following SQL features:

• ” : single quotes.

• "" : double quotes.

• “ : grave quotes (non-standard).

• -- : line comments.

• /* : block comments.

• :: : Postgres-style cast operator (non-standard).

In addition, it supports the following:

• () : content in parens.

• [] : content in brackets.

• {} : content in braces.

• $1 $2 ... : ordinal parameter placeholders.

• :identifier : named parameter placeholders.

Supporting SQL quotes and comments allows us to correctly ignore text inside special delimiters that happens to be part of a string, quoted identifier, or comment.

Usage

Oversimplified example:

nodes, err := Parse(`select * from some_table where :ident::uuid = id`)
panic(err)

err := TraverseDeep(nodes, func(ptr *Node) error {
	name, ok := (*ptr).(NodeNamedParam)
	if ok {
		// Guaranteed to break the query.
		*ptr = name + `_renamed`
	}
	return nil
})
panic(err)

sql := nodes.String()

The AST now looks like this:

nodes := Nodes{
	NodeText(`select * from some_table where `),
	NodeNamedParam(`ident_renamed`),
	NodeDoubleColon{},
	NodeText(`uuid = id`),
}

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Traverse

func Traverse(nodes Nodes, fun func(*Node) error) error

Performs a shallow traversal, invoking `fun` for each node.

func TraverseDeep

func TraverseDeep(nodes Nodes, fun func(*Node) error) error

Similar to `Traverse`, but deep. Calls `fun` for each leaf node, and ONLY for leaf nodes.

Types

type Error

type Error struct {
	Cause error
	// contains filtered or unexported fields
}

Parsing error. Includes the parser state corresponding to the place where the error had occurred. The parser state should be used for detailed error printing (but isn't yet).

func (*Error) Error

func (self *Error) Error() string

Prints the error message. Should include parser context such as line, column, and surrounding text, but doesn't yet.

func (*Error) Format

func (self *Error) Format(fms fmt.State, verb rune)

Fancier printing.

TODO: support '#' properly; include parser context such as line, column, and surrounding text.

type Node

type Node fmt.Stringer

Any AST node.

func FirstLeaf

func FirstLeaf(nodes Nodes) Node

Returns the first leaf node from the provided AST, or nil.

func LastLeaf

func LastLeaf(nodes Nodes) Node

Returns the last leaf node from the provided AST, or nil.

type NodeBraces

type NodeBraces []Node

Nodes enclosed in braces: {}.

func (NodeBraces) String

func (self NodeBraces) String() string

Implement the `Node` interface.

type NodeBrackets

type NodeBrackets []Node

Nodes enclosed in brackets: [].

func (NodeBrackets) String

func (self NodeBrackets) String() string

Implement the `Node` interface.

type NodeCommentBlock

type NodeCommentBlock string

Content of a block comment: /* */.

func (NodeCommentBlock) String

func (self NodeCommentBlock) String() string

Implement the `Node` interface.

type NodeCommentLine

type NodeCommentLine string

Content of a line comment: --, including the newline.

func (NodeCommentLine) String

func (self NodeCommentLine) String() string

Implement the `Node` interface.

type NodeDoubleColon

type NodeDoubleColon struct{}

Postgres type cast operator: ::.

func (NodeDoubleColon) String

func (self NodeDoubleColon) String() string

Implement the `Node` interface.

type NodeNamedParam

type NodeNamedParam string

Named parameter preceded by colon: :identifier.

func (NodeNamedParam) String

func (self NodeNamedParam) String() string

Implement the `Node` interface.

type NodeOrdinalParam

type NodeOrdinalParam uint

Postgres-style ordinal parameter placeholder: $1, $2, $3, ...

func (NodeOrdinalParam) String

func (self NodeOrdinalParam) String() string

Implement the `Node` interface.

type NodeParens

type NodeParens []Node

Nodes enclosed in parentheses: ().

func (NodeParens) String

func (self NodeParens) String() string

Implement the `Node` interface.

type NodeQuoteDouble

type NodeQuoteDouble string

Text inside double quotes: "". Escape sequences are not supported yet.

func (NodeQuoteDouble) String

func (self NodeQuoteDouble) String() string

Implement the `Node` interface.

type NodeQuoteGrave

type NodeQuoteGrave string

Text inside grave quotes: “. Escape sequences are not supported yet.

func (NodeQuoteGrave) String

func (self NodeQuoteGrave) String() string

Implement the `Node` interface.

type NodeQuoteSingle

type NodeQuoteSingle string

Text inside single quotes: ”. Escape sequences are not supported yet.

func (NodeQuoteSingle) String

func (self NodeQuoteSingle) String() string

Implement the `Node` interface.

type NodeText

type NodeText string

Arbitrary text. Anything that wasn't recognized by the parser.

func (NodeText) String

func (self NodeText) String() string

Implement the `Node` interface.

type Nodes

type Nodes []Node

Arbitrary sequence of AST nodes. This is the main AST type, used by `Parse()`, `Traverse()`, and some other functions.

func CopyDeep

func CopyDeep(src Nodes) Nodes

Makes a deep copy of the input AST. Useful when you plan to mutate one but keep the other.

func Parse

func Parse(input string) (Nodes, error)

Parses a query and returns the AST. For the AST structure, see `Node` and the various node types.

Example:

ast, err := Parse(`select * from some_table where id = :ident`)
panic(err)

// Non-recursive example for simplicity.
for i, node := range ast {
	switch node.(type) {
	case NodeNamedParam:
		ast[i] = NodeOrdinalParam(1)
	}
}

sql := ast.String()

func (Nodes) String

func (self Nodes) String() string

Implement the `Node` interface. Simply concatenates the stringified representations of the inner nodes, skipping any nil nodes.

`Nodes` can be arbitrarily nested without affecting the output. For example, both `Nodes{}` and `Nodes{Nodes{}}` will print "".

Jump to

Keyboard shortcuts

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