Documentation
¶
Overview ¶
Package enjinql provides an abstracted system for indexing and querying a collection of content.
Sources is an interface for managing and querying a collection of Source instances.
Source is an interface for managing the correlation of contextual information with the collection of content.
Source Forms ¶
There are currently three forms of what a Source is, conceptually speaking.
The first is the "primary source" that the Enjin Query Language is tasked with indexing. This is not the actual data being stored in a table per-se, just the necessary bits for providing a reference back to the actual content (like most other indexing systems). For example, in the use of the fantastic bleve search system, the site developer must provide a mapping of fields to index and then for each url of content, pass the url and its specific fields to bleve to index. bleve analyses the individual fields of content and using its internal primary source (likely a btree or some other wizardry), links this listing of URLs to the content fields provided. Once the site indexing process is complete, the developer can easily produce a search page which end-users can use the bleve search syntax to find content present in the site.
For the Enjin Query Language, more than just the URL is important. There is still the URL of course but there is a greater context present as well. There is the page's shasum identifier, the page's type of content, language and so on to form a contextual index for finding content. This isn't to replace bleve within Go-Enjin; end-user search features are notoriously difficult to get right and bleve excels at getting this right. As a developer of a Go-Enjin based system, writing features often requires querying the enjin for a contextual case that may not involve the URL at all and to be forced to query for a URL in order to query for a page's specific context becomes a rather tedious repetition of code that isn't easily abstracted. Cases like that are examples of what could be called the farming of technical debt. Of course developers don't like farming technical debt and because one of the main purposes of the Go-Enjin project is to cater to the needs of the developer rather than just the employers and end-users, Go-Enjin necessitates a system for managing and querying a context of information.
The second form of Source is the "data source". These are sources of data that relate to the primary source but do not actually have any direct correlation with the primary source context. For example, if the developer needs to build up a list of distinct words found within any given page of content, it is beneficial to have an index of all distinct words in general and to then use another form of source which joins the data source with the primary source.
The final form of Source is the "link source" and as noted in the data source description, these sources typically have only unique identifiers which link two data sources together. This is the basis for how the Enjin Query Language can construct SQL queries with multiple JOIN statements without the developer having to spell out the table relationships in their use of the Enjin Query Language.
Real World Example ¶
One of the Go-Enjin website projects is an experiment in exploring human thought through the strange indexing of a large set of quotes from various sources. This website is called Quoted.FYI and in specific, it allows visitors to select from a list of "first words" from all quotes and then select from another list of "next words", and so on, building up to a narrow selection of quotes sharing the same series of opening words. To implement this feature, systems like bleve just aren't designed for it. Let's take a little walkthrough of the Quoted.FYI website project.
## Quotes
- a quote is just a normal Go-Enjin page with a custom type of "quote"
- each quote has a context consisting of an author, a list of topics, the body of the quote and a SHA1 hashing of the content (used to help avoid exact duplicates though "plural specificity" is allowed)
## Statistics
- 482,673 quotes
- 23,731 authors
- 11,980 topics
- 98,879 words
## EnjinQL Setup
Quoted.FYI of course uses the default Go-Enjin primary source which consists of a number of specific columns of information related to any given page.
| (Page Primary Source) | | Key | Description | ---------------------------------------------------------- | id | an integer primary key | | shasum | specific version of a specific page | | language | language code of a specific page | | url | relative URL path to a specific page | | stub | JSON blob used to construct a specific page |
These are the commonly used context keys when implementing Go-Enjin features, and so they're all a part of the primary enjinql source.
For each of the authors, topics and words information, Quoted.FYI needs additional indexing to support these various things. They're relatively the same but let's take a look at the words indexing in more detail.
| (Word Data Source) | | Key | Description | --------------------------------------------------------------- | id | an integer primary key | | word | lower-cased plain text, unique, word | | flat | a snake_cased version of word used in legacy URLs |
The above data source, describes the list of distinct words used to consolidate the space required by the underlying database.
So, now there are two sources defined, the primary one and the list of unique words. These two sources, being entirely unrelated to each other would result in a query error if used together.
For example, to look up a list of page shasums for the "en" language:
(EQL) LOOKUP .Shasum WITHIN .Language == "en" (SQL) SELECT be_eql_page.shasum FROM be_eql_page WHERE be_eql_page.language = "en";
The above query would work and return the list of all page shasums that are of the "en" language.
(EQL) LOOKUP word.Word WITHIN .Word ^= "a" (SQL) SELECT be_eql_word.word FROM be_eql_word WHERE be_eql_word LIKE "a%";
The above query again would work, this time returning a list of all words starting with the letter "a". While not the most efficient due to the use of the "starts with" (^=) operator, it does perform well.
Given just the primary and word data sources, the following query would not work (yet):
(EQL) LOOKUP .Shasum WITHIN word.Word == "thing" (SQL) error: "be_eql_page" is not linked with "be_eql_word"
The above query is supposed to return a list of page shasums where the page uses the word "thing" at least once. To make this work, the needs to be a link source connecting the relationship of pages to words within each page.
| (Page Words Link Source) | | Key | Description | ------------------------------------------------------------- | id | an integer primary key | | page_id | id of the primary source | | word_id | id of the word data source | | hits | how many times the word is used within the page |
The above link source joins the primary source with the word data source and includes an extra count of how many times that specific word is used within the specific quote.
Now, the query to get the list of pages with the word "thing":
(EQL) LOOKUP .Shasum WITHIN word.Word == "thing" (SQL) SELECT be_eql_page.shasum FROM be_eql_page INNER JOIN be_eql_page_words ON be_eql_page.id=be_eql_page_words.page_id INNER JOIN be_eql_words ON be_eql_word.id=be_eql_page_words.word_id WHERE be_eql_word.word == "thing";
This demonstrates the simplicity of the Enjin Query Language in that the EQL statements don't need to do an SQL magic directly, such as sorting out the table joins. This is all done by the developer simply defining the various sources and then populating them with the content available.
The below code demonstrates how to create the primary and word data sources depicted above:
// this is the top-level interface for interacting with the enjinql module sources := enjinql.NewSources("be_eql") // build the primary source bePage, err := sources.newSource("page"). StringValue("shasum", 10). // shasum primary value (10 bytes) AddStringValue("language", 7). // page language code (7 bytes) AddStringValue("type", 32). // custom page type (32 bytes) AddStringValue("url", 2000). // page url (2000 bytes) AddStringValue("stub", -1). // enjin stub (default TEXT size) AddUnique("shasum", "language", "url"). // add a UNIQUE constraint on shasum + language + url AddIndex("shasum"). // add a specific shasum sql index AddIndex("language"). // add a specific language sql index AddIndex("type"). // add a specific type sql index AddIndex("url"). // add a specific url sql index Make() // make the source instance // build the word data source beWord, err := sources.newSource("word"). StringValue("word", 256). // word primary value (256 bytes) AddStringValue("flat", 256). // flat word value (256 bytes) AddUnique("word"). // add a UNIQUE constraint on word AddIndex("word"). // add a specific word sql index AddIndex("flat"). // add a specific flat sql index Make() // make the source instance // build the page-word link source bePageWords, err := bePage.newSource("words"). LinkedValue("page", "id"). // page_id link to bePage source, id column AddLinkedValue("word", "id"). // word_id link to "word" source, id column AddIntValue("hits"). // additional integer value AddUnique("page_id", "word_id"). // add a UNIQUE constraint on page_id + word_id AddIndex("page_id"). // add a specific page_id index AddIndex("word_id"). // add a specific word_id index Make() // make the source instance
With the above constructed, the developer can now proceed with updating the sources instance with the content available.
// add a new page to the primary source sid, err = bePage.Insert("1234567890", "en", "quote", "/q/a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2", "{...json...}") // for each of the distinct words present in the quote body, count the number of times the word is used, flatten // the word and add it all to the word source wid, err = beWord.InsertOrIgnore("word", "i'm", "i_m") _, err = bePageWord.Insert(sid, wid, count)
That process needs to be expanded up of course for the complete site, but for just the primary, data and link sources defined so far, the enjinql instance is now ready to build the actual SQL from parsing EQL statements:
// get a list of shasums for all pages with the word "thing" sql, argv, err = sources.Parse(`LOOKUP .Shasum WITHIN word.Word == "thing"`) // sql => "SELECT ... WHERE be_eql_word.word=?;" // argv => []interface{"thing"} // err => nil
Code generated by Participle. DO NOT EDIT.
Index ¶
- Constants
- Variables
- func GetLexerJSON() (text string)
- func GetSyntaxEBNF() (ebnf string)
- func PrepareSyntax(format string, argv ...interface{}) (prepared string, err error)
- func SkipCreateIndex(o *option) (err error)
- func SkipCreateTable(o *option) (err error)
- type Boolean
- type Condition
- type Config
- func (c *Config) AddSource(source *SourceConfig) *Config
- func (c *Config) Clone() (cloned *Config)
- func (c *Config) Make() (config *Config, err error)
- func (c *Config) NewSource(name string) (source *SourceConfig)
- func (c *Config) Serialize() (output string)
- func (c *Config) String() (output string)
- func (c *Config) Validate() (err error)
- type ConfigSourceValues
- type ConfigSources
- func (s ConfigSources) Clone() (cloned ConfigSources)
- func (s ConfigSources) DataNames() (names []string)
- func (s ConfigSources) Get(name string) (cloned *SourceConfig)
- func (s ConfigSources) JoinNames() (names []string)
- func (s ConfigSources) LinkNames() (names []string)
- func (s ConfigSources) Names() (names []string)
- type Constraint
- type EnjinQL
- type Expression
- type Null
- type Operator
- type Option
- type OrderBy
- type Shell
- type SourceConfig
- func (sc *SourceConfig) AddIndex(keys ...string) *SourceConfig
- func (sc *SourceConfig) AddUnique(keys ...string) *SourceConfig
- func (sc *SourceConfig) AddValue(v *SourceConfigValue) *SourceConfig
- func (sc *SourceConfig) Clone() (cloned *SourceConfig)
- func (sc *SourceConfig) DoneSource() *Config
- func (sc *SourceConfig) NewBoolValue(key string) *SourceConfig
- func (sc *SourceConfig) NewFloatValue(key string) *SourceConfig
- func (sc *SourceConfig) NewIntValue(key string) *SourceConfig
- func (sc *SourceConfig) NewLinkedValue(table, key string) *SourceConfig
- func (sc *SourceConfig) NewStringValue(key string, size int) *SourceConfig
- func (sc *SourceConfig) SetParent(name string) *SourceConfig
- func (sc *SourceConfig) Type() (t SourceConfigType)
- type SourceConfigType
- type SourceConfigValue
- func NewBoolValue(key string) *SourceConfigValue
- func NewFloatValue(key string) *SourceConfigValue
- func NewIntValue(key string) *SourceConfigValue
- func NewLinkedValue(source, key string) *SourceConfigValue
- func NewStringValue(key string, size int) *SourceConfigValue
- func NewTimeValue(key string) *SourceConfigValue
- type SourceConfigValueBool
- type SourceConfigValueFloat
- type SourceConfigValueInt
- type SourceConfigValueLinked
- type SourceConfigValueString
- type SourceConfigValueTime
- type SourceKey
- type SourceRef
- type SqlDB
- type SqlTX
- type SqlTrunkTX
- type SrcKey
- type Syntax
- type SyntaxError
- type Value
Constants ¶
const ( PageSource = "page" PageSourceIdKey = "page_id" PageShasumKey = "shasum" PageLanguageKey = "language" PageTypeKey = "type" PageArchetypeKey = "archetype" PageCreatedKey = "created" PageUpdatedKey = "updated" PageUrlKey = "url" PageStubKey = "stub" )
const ( // MaxUrlPathSize is the recommended 2000-character limit on overall URL // size, minus 256 for the domain segment and minus another nine for the // https:// MaxUrlPathSize = 2000 - 256 - 8 // MaxPageTypeSize is the Go-Enjin recommended 64-character limit on the // total length of custom page type and archetype names MaxPageTypeSize = 64 // PageShasumSize is the length of a Go-Enjin page "shasum" identifier, // which is the first 10-characters of the SHA-256 hash of the complete // page content (front-matter plus body) PageShasumSize = 10 )
const ( PagePermalinkSource = "permalink" PagePermalinkShortKey = "short" PagePermalinkLongKey = "long" ShortPermalinkSize = 10 // size of [shasum.BriefLength] LongPermalinkSize = 36 // length of hex-string uuid.V4 ((uuid.Size * 2) + 4) )
const ( PageRedirectSource = "redirect" PageRedirectKey = "url" )
const (
// SourceIdKey is the SQL name of the primary key for all SQL tables
SourceIdKey = "id"
)
Variables ¶
var ( ErrBuilderError = errors.New("builder error") ErrInvalidSyntax = errors.New("invalid syntax") ErrSyntaxValueType = errors.New("unsupported syntax value type") ErrNilStructure = errors.New("nil structure") ErrMismatchQuery = errors.New("QUERY does not return keyed values; use LOOKUP for context specifics") ErrMismatchLookup = errors.New("LOOKUP does not return entire pages; use QUERY for complete pages") ErrNegativeOffset = errors.New("negative offset") ErrNegativeLimit = errors.New("negative limit") ErrMissingSourceKey = errors.New("missing source key") ErrMissingOperator = errors.New("missing operator") ErrMissingLeftSide = errors.New("missing left-hand side expression") ErrMissingRightSide = errors.New("missing right-hand side expression") ErrInvalidConstraint = errors.New("invalid constraint") ErrInvalidInOp = errors.New("<SourceKey> [NOT] IN (<list>...)") ErrOpStringRequired = errors.New("operator requires a string argument") ErrTableNotFound = errors.New("table not found") ErrColumnNotFound = errors.New("column not found") ErrInvalidJSON = errors.New("invalid json data") ErrInvalidConfig = errors.New("invalid config") ErrNoSources = errors.New("at least one source is required") ErrNoSourceValues = errors.New("at least one source value is required") ErrParentNotFound = errors.New("parent not found") ErrNotSnakeCased = errors.New("all names and keys must be snake_cased") ErrUnnamedSource = errors.New("unnamed source") ErrEmptySourceValue = errors.New("empty source value") ErrEmptySourceValueKey = errors.New("source value key is empty") ErrSourceNotFound = errors.New("source not found") ErrColumnConfigNotFound = errors.New("column config not found") ErrCreateIndexSQL = errors.New("error building create index sql") ErrCreateIndex = errors.New("error creating index sql") ErrCreateTableSQL = errors.New("error building create table sql") ErrCreateTable = errors.New("error creating table sql") ErrQueryRequiresStub = errors.New("eql query statements require a \"stub\" column") ErrDeleteRows = errors.New("delete rows error") ErrInsertRow = errors.New("insert row error") ErrTooManyValues = errors.New("too many values given") ErrNoValues = errors.New("at least the first column value is required") ErrInvalidID = errors.New("row identifiers must be greater than zero") ErrUnmarshalEnjinQL = errors.New("use enjinql.ParseConfig and enjinql.New to restore an EnjinQL instance") )
Functions ¶
func GetLexerJSON ¶
func GetLexerJSON() (text string)
GetLexerJSON returns a JSON representation of the syntax lexer
func GetSyntaxEBNF ¶
func GetSyntaxEBNF() (ebnf string)
GetSyntaxEBNF returns the EBNF text representing the Enjin Query Language
func PrepareSyntax ¶
func SkipCreateIndex ¶
func SkipCreateIndex(o *option) (err error)
func SkipCreateTable ¶
func SkipCreateTable(o *option) (err error)
Types ¶
type Condition ¶
type Condition struct { Left *Expression `parser:" '(' @@ ')' " json:"left"` Type string `parser:" @( 'AND' | 'OR' ) " json:"type"` Right *Expression `parser:" '(' @@ ')' " json:"right"` Pos lexer.Position }
Condition is the AND/OR combining of two expressions
type Config ¶
type Config struct { Prefix string `json:"prefix,omitempty"` Sources ConfigSources `json:"sources,omitempty"` }
Config is the structure for configuring a New EnjinQL instance
Config structures can be constructed manually, simply instantiate the Go types and build the structure directly. To check for errors, call the Config.Validate method.
Another way to create Config structures is with JSON and using ParseConfig to both unmarshal and validate the resulting Config instance.
The last way is to use the builder methods in a long chain to build the Config programmatically
For example, to recreate a config with the default PageSource and others for the page titles and descriptions:
bePage, err := NewConfig("be_eql"). // start building a Config NewSource("page"). // start building the SourceConfig AddStringValue("shasum", 10). // add shasum column AddStringValue("language", 10). // add language code column AddStringValue("type", 48). // add page type column AddStringValue("url", 1024). // add page URL path column AddStringValue("stub", -1). // add page stub column DoneSource(). // done making this particular source NewSource("extra"). // start another SourceConfig AddStringValue("title", 200). // add the title column AddStringValue("description", -1). // add the description DoneSource(). // done making this particular source Make()
func NewConfig ¶
NewConfig returns a new Config instance with only the given prefix set. All prefix values given are combined into a single snake_cased prefix string
func ParseConfig ¶
ParseConfig unmarshalls the given JSON data into a new Config instance
func (*Config) AddSource ¶
func (c *Config) AddSource(source *SourceConfig) *Config
func (*Config) NewSource ¶
func (c *Config) NewSource(name string) (source *SourceConfig)
func (*Config) Serialize ¶
Serialize is a convenience method for returning (unindented) JSON data representing this Config instance, use ParseConfig to restore the Config
type ConfigSourceValues ¶
type ConfigSourceValues []*SourceConfigValue
ConfigSourceValues is a slice type for providing Config builder methods
func (ConfigSourceValues) Clone ¶
func (v ConfigSourceValues) Clone() (cloned ConfigSourceValues)
func (ConfigSourceValues) HasLinks ¶
func (v ConfigSourceValues) HasLinks() (linked bool)
func (ConfigSourceValues) Names ¶
func (v ConfigSourceValues) Names() (names []string)
type ConfigSources ¶
type ConfigSources []*SourceConfig
ConfigSources is a slice type for providing Config builder methods
func (ConfigSources) Clone ¶
func (s ConfigSources) Clone() (cloned ConfigSources)
func (ConfigSources) DataNames ¶
func (s ConfigSources) DataNames() (names []string)
DataNames returns a list of all data source names (sources with no parent), in the order they were added
func (ConfigSources) Get ¶
func (s ConfigSources) Get(name string) (cloned *SourceConfig)
Get returns a clone of the named SourceConfig
func (ConfigSources) JoinNames ¶
func (s ConfigSources) JoinNames() (names []string)
JoinNames returns a list of all link source names (sources with a parent and has at least one value linked), in the order they were added
func (ConfigSources) LinkNames ¶
func (s ConfigSources) LinkNames() (names []string)
LinkNames returns a list of all link source names (sources with a parent or has at least one value linked), in the order they were added
func (ConfigSources) Names ¶
func (s ConfigSources) Names() (names []string)
Names returns a list of all source names, in the order they were added
type Constraint ¶
type Constraint struct { Left *SourceRef `parser:" @@ " json:"left"` Op *Operator `parser:" ( ( @@ " json:"op,omitempty"` Right *Value `parser:" @@ ) " json:"right,omitempty"` Not bool `parser:" | ( @'NOT'? " json:"not,omitempty"` In bool `parser:" @'IN' " json:"in,omitempty"` Values []*Value `parser:" '(' @@ ( ',' @@ )* ')' ) ) " json:"values,omitempty"` Pos lexer.Position }
Constraint is the comparing of two values
func (*Constraint) String ¶
func (c *Constraint) String() (out string)
type EnjinQL ¶
type EnjinQL interface { // Parse parses the Enjin Query Language format string and constructs a // new Syntax instance Parse(format string, args ...interface{}) (parsed *Syntax, err error) // ParsedToSql prepares the SQL query arguments from a parsed Syntax tree ParsedToSql(parsed *Syntax) (query string, argv []interface{}, err error) // ToSQL uses Parse and ParsedToSQL to produce the SQL query arguments ToSQL(format string, args ...interface{}) (query string, argv []interface{}, err error) // Perform uses ToSQL to build and execute the SQL statement Perform(format string, argv ...interface{}) (columns []string, results context.Contexts, err error) // Plan uses Parse to prepare the Syntax tree, then prepares the SQL table // INNER JOIN statement plan and returns two summaries of the resulting // plan: a brief one-liner and a verbose multi-line Plan(format string, args ...interface{}) (brief, verbose string, err error) // DBH returns either the current sql.Tx or the default sql.DB instance DBH() SqlDB // T returns the sqlbuilder.Table associated with the named source, // returns nil if the table or source do not exist T(name string) (t sqlbuilder.Table) // SqlBuilder returns a sqlbuilder.Buildable instance, preconfigured with // the EnjinQL sqlbuilder.Dialect SqlBuilder() sqlbuilder.Buildable // SqlDialect returns the configured go-sqlbuilder dialect SqlDialect() sqlbuilder.Dialect // SqlBegin starts and returns new SQL transaction, this is the only way // to properly add or remove data from indexing SqlBegin() (tx SqlTrunkTX, err error) // SqlExec is a convenience wrapper around sql.DB.Exec which returns the // sql.Result values in one step SqlExec(query string, argv ...interface{}) (id int64, affected int64, err error) // SqlQuery is a convenience wrapper around sql.DB.Query which returns // the column order and results SqlQuery(query string, argv ...interface{}) (columns []string, results context.Contexts, err error) // String returns an indented JSON representation of the Config String() string // Marshal returns a compact JSON representation of the Config Marshal() (data []byte, err error) // Unmarshal always returns the ErrUnmarshalEnjinQL error Unmarshal(data []byte) (err error) // Config returns a clone of this EnjinQL instance's configuration Config() (cloned *Config) // CreateTables will process all configured sources and issue CREATE TABLE // IF NOT EXISTS queries, stopping at the first error CreateTables() (err error) // CreateIndexes will process all configured sources and issue CREATE // INDEX IF NOT EXISTS queries, stopping at the first error CreateIndexes() (err error) // Close calls the Close method on the sql.DB instance and flags this // enjinql instance as being closed Close() (err error) // Ready returns nil if this EnjinQL instance has an open sql.DB instance // and returns sql.ErrConnDone otherwise Ready() error // contains filtered or unexported methods }
EnjinQL is the interface for a built enjinql instance
type Expression ¶
type Expression struct { Constraint *Constraint `parser:" @@ " json:"operation,omitempty"` Condition *Condition `parser:" | @@ " json:"condition,omitempty"` Pos lexer.Position }
func (*Expression) String ¶
func (e *Expression) String() (out string)
type Operator ¶
type Operator struct { EQ bool `parser:" ( @'==' " json:"eq,omitempty"` NE bool `parser:" | @( '!=' | '<>' ) " json:"ne,omitempty"` GE bool `parser:" | @'>=' " json:"ge,omitempty"` LE bool `parser:" | @'<=' " json:"le,omitempty"` GT bool `parser:" | @'>' " json:"gt,omitempty"` LT bool `parser:" | @'<' " json:"lt,omitempty"` Not bool `parser:" ) | ( ( @( 'NOT' ) " json:"not,omitempty"` Nt bool `parser:" | @( '!' ) )? " json:"nt,omitempty"` LK bool `parser:" ( @'LIKE' " json:"lk,omitempty"` SW bool `parser:" | @'^=' " json:"sw,omitempty"` EW bool `parser:" | @'$=' " json:"ew,omitempty"` CS bool `parser:" | @'*=' " json:"cs,omitempty"` CF bool `parser:" | @'~=' ) ) " json:"cf,omitempty"` Pos lexer.Position }
Operator represents a comparison operation
| Key | Op | Description | +-----+------+--------------------------+ | EQ | == | equal to | | NE | != | not equal to | | GE | >= | greater than or equal to | | LE | <= | less than or equal to | | GT | > | greater than | | LT | < | less than | | LK | LIKE | like | | SW | ^= | starts with | | EW | $= | ends with | | CS | *= | contains one of string | | CF | ~= | contains any of fields |
For LK, SW, EW, CS and CF, there is a NOT modifier:
| Key | Op | Description | +-----+------+--------------------------+ | Not | NOT | long-form negate | | Nt | ! | short-form negate |
Example NOT modifier usage:
| Example | Description | +---------+---------------------+ | NOT ^= | does not start with | | !$= | does not end with |
type OrderBy ¶
type Shell ¶
type Shell interface { // Run starts the interactive shell Run() // Stop stops the interactive shell Stop() // Close shuts down the shell completely Close() // Process runs shell using arguments in non-interactive mode Process(argv ...string) (err error) }
Shell is a simple interface for managing an interactive eql shell session
type SourceConfig ¶
type SourceConfig struct { Name string `json:"name"` Parent *string `json:"parent,omitempty"` Values ConfigSourceValues `json:"values"` Unique [][]string `json:"unique,omitempty"` Index [][]string `json:"index,omitempty"` // contains filtered or unexported fields }
SourceConfig is the structure for configuring a specific source
func MakeSourceConfig ¶
func MakeSourceConfig(parent, name string, primary *SourceConfigValue, additional ...*SourceConfigValue) (sc *SourceConfig)
MakeSourceConfig is a convenience wrapper for constructing SourceConfig instances. Will panic if the primary value is nil.
func PagePermalinkSourceConfig ¶
func PagePermalinkSourceConfig() (sc *SourceConfig)
func PageRedirectSourceConfig ¶
func PageRedirectSourceConfig() (sc *SourceConfig)
func PageSourceConfig ¶
func PageSourceConfig() (sc *SourceConfig)
PageSourceConfig returns a new SourceConfig, preset with the primary source settings required for the Go-Enjin project. The page SourceConfig is preset with five columns in addition to the default id column present with all sources:
+------+-----------+-------------------------------------------+ | size | column | description | +------+-----------+-------------------------------------------+ | 10 | shasum | a unique identifier used within Go-Enjin | | 10 | language | the language code for a page | | 64 | type | the type of page | | 64 | archetype | the page archetype | | 2000 | url | the URL path (absolute) to a page | | -1 | stub | JSON context for filesystem lookup | +------+-----------+-------------------------------------------+
func (*SourceConfig) AddIndex ¶
func (sc *SourceConfig) AddIndex(keys ...string) *SourceConfig
AddIndex adds the given keys to the list of indexes
func (*SourceConfig) AddUnique ¶
func (sc *SourceConfig) AddUnique(keys ...string) *SourceConfig
AddUnique add the given keys to the list of unique constraints
func (*SourceConfig) AddValue ¶
func (sc *SourceConfig) AddValue(v *SourceConfigValue) *SourceConfig
AddValue adds the given SourceConfigValue
func (*SourceConfig) Clone ¶
func (sc *SourceConfig) Clone() (cloned *SourceConfig)
func (*SourceConfig) DoneSource ¶
func (sc *SourceConfig) DoneSource() *Config
DoneSource completes this SourceConfig builder chain
func (*SourceConfig) NewBoolValue ¶
func (sc *SourceConfig) NewBoolValue(key string) *SourceConfig
func (*SourceConfig) NewFloatValue ¶
func (sc *SourceConfig) NewFloatValue(key string) *SourceConfig
func (*SourceConfig) NewIntValue ¶
func (sc *SourceConfig) NewIntValue(key string) *SourceConfig
func (*SourceConfig) NewLinkedValue ¶
func (sc *SourceConfig) NewLinkedValue(table, key string) *SourceConfig
NewLinkedValue adds a cross-table link to another source
func (*SourceConfig) NewStringValue ¶
func (sc *SourceConfig) NewStringValue(key string, size int) *SourceConfig
NewStringValue adds a string value column with the given size. If the size is less-than or equal-to zero, the column will be some sort of TEXT type depending on the specific SQL service used
func (*SourceConfig) SetParent ¶
func (sc *SourceConfig) SetParent(name string) *SourceConfig
SetParent configures the SourceConfig.Parent setting
func (*SourceConfig) Type ¶
func (sc *SourceConfig) Type() (t SourceConfigType)
type SourceConfigType ¶
type SourceConfigType uint8
const ( UnknownSourceType SourceConfigType = iota // DataSourceType represents sources that have no parent and no linked values DataSourceType // LinkSourceType represents sources that have a parent or have linked values LinkSourceType // JoinSourceType represents sources that have a parent and have liked values JoinSourceType )
func (SourceConfigType) String ¶
func (t SourceConfigType) String() (name string)
type SourceConfigValue ¶
type SourceConfigValue struct { Int *SourceConfigValueInt `json:"int,omitempty"` Bool *SourceConfigValueBool `json:"bool,omitempty"` Time *SourceConfigValueTime `json:"time,omitempty"` Float *SourceConfigValueFloat `json:"float,omitempty"` String *SourceConfigValueString `json:"string,omitempty"` Linked *SourceConfigValueLinked `json:"linked,omitempty"` // contains filtered or unexported fields }
SourceConfigValue is the structure for configuring a specific value indexed by the SourceConfig
func NewBoolValue ¶
func NewBoolValue(key string) *SourceConfigValue
NewBoolValue is a convenience wrapper to construct a boolean SourceConfigValue
func NewFloatValue ¶
func NewFloatValue(key string) *SourceConfigValue
NewFloatValue is a convenience wrapper to construct a decimal SourceConfigValue
func NewIntValue ¶
func NewIntValue(key string) *SourceConfigValue
NewIntValue is a convenience wrapper to construct an integer SourceConfigValue
func NewLinkedValue ¶
func NewLinkedValue(source, key string) *SourceConfigValue
NewLinkedValue is a convenience wrapper to construct a linked SourceConfigValue
func NewStringValue ¶
func NewStringValue(key string, size int) *SourceConfigValue
NewStringValue is a convenience wrapper to construct a string SourceConfigValue
func NewTimeValue ¶
func NewTimeValue(key string) *SourceConfigValue
NewTimeValue is a convenience wrapper to construct a boolean SourceConfigValue
func (*SourceConfigValue) Clone ¶
func (scv *SourceConfigValue) Clone() (cloned *SourceConfigValue)
func (*SourceConfigValue) Name ¶
func (scv *SourceConfigValue) Name() (output string)
type SourceConfigValueBool ¶
type SourceConfigValueBool struct { Key string `json:"key"` // contains filtered or unexported fields }
type SourceConfigValueFloat ¶
type SourceConfigValueFloat struct { Key string `json:"key"` // contains filtered or unexported fields }
type SourceConfigValueInt ¶
type SourceConfigValueInt struct { Key string `json:"key"` // contains filtered or unexported fields }
type SourceConfigValueLinked ¶
type SourceConfigValueString ¶
type SourceConfigValueTime ¶
type SourceConfigValueTime struct { Key string `json:"key"` // contains filtered or unexported fields }
type SourceKey ¶
type SourceRef ¶
type SqlDB ¶
type SqlDB interface { Perform(format string, argv ...interface{}) (columns []string, results clContext.Contexts, err error) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) Prepare(query string) (*sql.Stmt, error) ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error) Exec(query string, args ...any) (sql.Result, error) QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error) Query(query string, args ...any) (*sql.Rows, error) QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row QueryRow(query string, args ...any) *sql.Row }
type SqlTrunkTX ¶
type Syntax ¶
type Syntax struct { Lookup bool `parser:" ( ( @'LOOKUP' " json:"lookup,omitempty"` Count bool `parser:" @'COUNT'? " json:"count,omitempty"` Distinct bool `parser:" @'DISTINCT'? " json:"distinct,omitempty"` Keys []*SourceKey `parser:" @@ ( ',' @@ )* ) " json:"keys,omitempty"` Query bool `parser:" | @'QUERY' ) " json:"query,omitempty"` Within *Expression `parser:" ( 'WITHIN' @@ )? " json:"within,omitempty"` OrderBy *OrderBy `parser:" ( @@ )? " json:"orderBy,omitempty"` Offset *int `parser:" ( 'OFFSET' @Int )? " json:"offset,omitempty"` Limit *int `parser:" ( 'LIMIT' @Int )? " json:"limit,omitempty"` Semicolon bool `parser:" ( @';' )? " json:"semicolon,omitempty"` Pos lexer.Position }
func ParseSyntax ¶
ParseSyntax parses the input string and returns an initialized Syntax tree
type SyntaxError ¶
func (*SyntaxError) Err ¶
func (e *SyntaxError) Err() error
func (*SyntaxError) Error ¶
func (e *SyntaxError) Error() string
type Value ¶
type Value struct { Text *string `parser:" @String " json:"text,omitempty"` Int *int `parser:" | @Int " json:"int,omitempty"` Float *float64 `parser:" | @Float " json:"float,omitempty"` Bool *Boolean `parser:" | @( 'TRUE' | 'FALSE' ) " json:"bool,omitempty"` Null *Null `parser:" | @( 'NIL' | 'NULL' ) " json:"nil,omitempty"` SourceRef *SourceRef `parser:" | @@ " json:"source,omitempty"` Placeholder *string `parser:" | @Placeholder " json:"placeholder,omitempty"` Pos lexer.Position }
Source Files
¶
- config-source-types.go
- config-source-value.go
- config-source-values.go
- config-source.go
- config-sources.go
- config.go
- config_default_page.go
- config_default_permalink.go
- config_default_redirect.go
- config_defaults.go
- config_validators.go
- docs.go
- enjinql-prepare-sql.go
- enjinql.go
- enjinql_graph.go
- enjinql_processor.go
- enjinql_source-value.go
- enjinql_source.go
- enjinql_sources.go
- errors.go
- shell-render.go
- shell.go
- sql-db.go
- sql-trunk-tx.go
- sql-tx.go
- syntax-parser.go
- syntax-parser_faster.go
- syntax-parser_faster_lexer.go
- syntax.go
- syntax_boolean.go
- syntax_condition.go
- syntax_constraint.go
- syntax_expression.go
- syntax_null.go
- syntax_operator.go
- syntax_order-by.go
- syntax_source-key.go
- syntax_source-ref.go
- syntax_src-key.go
- syntax_syntax-error.go
- syntax_value.go