The web version only has simple instructions since chapter 04, while the full book has detailed explanations and background info.

0506: WHERE Expression

Parse WHERE

This step adds no new features. It refactor the WHERE part into an expression.

type StmtSelect struct {
    table string
    cols  []interface{} // ExprUnOp | ExprBinOp | string | *Cell
    // keys  []NamedCell
    cond  interface{}
}

type StmtUpdate struct {
    table string
    // keys  []NamedCell
    cond  interface{}
    value []ExprAssign
}

type StmtDelete struct {
    table string
    // keys  []NamedCell
    cond  interface{}
}

Update parser:

func (p *Parser) parseSelect(out *StmtSelect) (err error) {
    // ...
    out.cond, err = p.parseWhere()
    return err
}

func (p *Parser) parseWhere() (expr interface{}, err error)

Match Expressions

During execution, extract primary key values from the expression:

func (db *DB) execSelect(stmt *StmtSelect) ([]Row, error) {
    // ...
    row, err := matchPKey(&schema, stmt.cond)
    if err != nil {
        return nil, err
    }
    if ok, err = db.Select(&schema, row); err != nil {
        return nil, err
    }
    // ...
}
func matchPKey(schema *Schema, cond interface{}) (Row, error) {
    if keys, ok := matchAllEq(cond, nil); ok {
        return makePKey(schema, keys)
    }
    return nil, errors.New("unimplemented WHERE")
}

matchAllEq() detects expressions like a = 123 AND b = 456 AND ... and outputs column names and values. It recursively walks the expression. Implement this:

func matchAllEq(cond interface{}, out []NamedCell) ([]NamedCell, bool)

For now, only primary key queries that return a single row are supported. To add other query types, you must recognize other expression forms, such as range queries in the next step.

CodeCrafters.io has similar courses in many programming languages, including build your own Redis, SQLite, Docker, etc. It’s worth checking out.