Skip to content

Latest commit

 

History

History
236 lines (174 loc) · 6.59 KB

README.md

File metadata and controls

236 lines (174 loc) · 6.59 KB

Espresso++

  1. Introduction
  2. Building Instructions
  3. Getting Started

Introduction

Espresso++ is a natural query language that abstracts away the native query language of any data management system.

This distro consists of both a library to be used by any client application that needs to support filtering and a command-line utility to help developers debug filters written in the Espresso++ language.

Further information about Espresso++ is available in the following documents:

Building Instructions

The Makefile that comes with this project supports the following targets:

  • all: Runs in sequence check, test, and install
  • get-tools: Retrieves and installs goimports
  • init: Creates go.mod if missing
  • build: Builds the espressopp utility in the out sub-directory
  • clean: Cleans the last build
  • test: Runs unit tests
  • install: Installs the espressopp utility into $GOPATH/bin
  • uninstall: Uninstalls the espressopp utility from $GOPATH/bin
  • docs: Runs in sequence docs-html and docs-pdf
  • docs-html: Generates HTML documentation in the out/html sub-directory
  • docs-pdf: Generates PDF documentation in the out/pdf sub-directory
  • fmt: Formats source code according to the Go best practices
  • simplify: Simplifies source code according to the Go best practices
  • check: Checks whether source code is well formatted

The Espesso++ library gets compiled together with the client application, therefore this build procedure only applies to espressopp, a command-line utility that takes an Espresso++ expression as an input and returns the resulting native query. To build and install espressopp into $GOPATH/bin, issue the following command – ensure you added GOPATH/bin to your PATH:

$ make install

Finally, to generate the HTML and PDF documentation in the out/docs sub-directory, issue the following command – ensure asciidoctor, asciidoctor-pdf, and asciidoctor-diagrams are installed on your system:

$ make docs

To generate HTML only:

$ make docs-html

To generate PDF only:

$ make docs-pdf

Getting Started

Currently Espresso++ suports just SQL, but the way a filter is create for data management systems with other query languages does not change. Below is an example of how to get an Espresso++ expression translated into SQL:

package main

import (
    "bytes"
    "fmt"
    "strings"

    "gitlab.com/skeeterhealth/espressopp"
)

func main() {
    ageProps := &espressopp.FieldProps{
        Filterable: true,       // whether "age" can be queried
        NativeName: "min_age",  // actual column name
    }

    r := strings.NewReader("age gte 30")
    w := new(bytes.Buffer)

    interpreter := espressopp.NewEspressoppInterpreter()
    codeGenerator := espressopp.NewSqlCodeGenerator()
    codeGenerator.RenderingOptions.AddFieldProps("age", ageProps)
    codeGenerator.RenderingOptions.EnableNamedParams()
    err := interpreter.Accept(codeGenerator, r, w)

    if err != nil {
        msg := fmt.Errorf("Error generating sql: %v", err)
        fmt.Println(msg)
    } else {
        // generated query contains named parameters instead of actual values
        fmt.Println(w.String())

        // list named parameter values associated with the generated query
        namedParamValues, _ := codeGenerator.RenderingOptions.GetNamedParamValues()
        for k, v := range namedParamValues {
            fmt.Printf("%s: %s\n", k, v)
        }
    }
}

If Espresso++ supported MongoDB, the client code would be something like this:

package main

import (
    "bytes"
    "fmt"
    "strings"

    "gitlab.com/skeeterhealth/espressopp"
)

func main() {
    ageProps := &espressopp.FieldProps{
        Filterable: true,       // whether "age" can be queried
        NativeName: "min_age",  // actual column name
    }

    r := strings.NewReader("age gte 30")
    w := new(bytes.Buffer)

    interpreter := espressopp.NewEspressoppInterpreter()
    codeGenerator := espressopp.NewMongoCodeGenerator()
    codeGenerator.RenderingOptions.AddFieldProps("age", ageProps)
    err := interpreter.Accept(codeGenerator, r, w)

    if err != nil {
        msg := fmt.Errorf("Error generating mongo: %v", err)
        fmt.Println(msg)
    } else {
        fmt.Println(w.String())
    }
}

Last but not least, developers can debug their Espresso++ expressions with the espressoppcommand-line utility:

$ espressopp --help

Usage: espressopp <command>

A utility that converts input Espresso++ expressions into native queries.

Flags:
  --help    Show context-sensitive help.

Commands:
  generate    Generate target native query.

Run "espressopp <command> --help" for more information on a command.

The generate command gets the target language and an Espresso++ expression as the input:

$ espressopp generate --help

Usage: espressopp generate <target> <expression> [<fieldmap> ...]

Generate target native query.

Arguments:
  <target>            Target query language.
  <expression>        Source expression.
  [<fieldmap> ...]    Mapping to native column names.

Flags:
  --help    Show context-sensitive help.

  -e, --enable-named-params    Enable named parameters.

For example, let's translate the Espresso++ expression age gte 30 and weight lt 80 into SQL:

$ espressopp generate sql "age gte 30 and weight lt 80"

age >= 30 AND weight < 80

And let's suppose the native column names differ from the field names in the Espresso++ expression:

$ espressopp generate sql "age gte 30 and weight lt 80" age=min_age weight=body_weight

min_age >= 30 AND body_weight < 80

Literals in the generated query can be replaced with named parameters to improve security:

$ espressopp generate sql -e "age gte 30 and weight lt 80" age=min_age weight=body_weight

min_age >= :P1 AND body_weigh < :P2

Named Parameters
================
P1: 30
P2: 80

Finally, the same Espresso++ expression translated into MongoDB query language:

$ espressopp generate mongo "age gte 30 and weight lt 80"

{ age: { $gte: 30 }, weight: { $lt: 80 } }

Copyright 2020 Skeeter Health