mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
162 lines
4.5 KiB
Go
162 lines
4.5 KiB
Go
// Copyright 2021 Molecula Corp. All rights reserved.
|
|
package sql
|
|
|
|
type router struct {
|
|
direct map[QueryMask]handler
|
|
filters []maskFilter
|
|
}
|
|
|
|
type maskFilter struct {
|
|
optional QueryMask
|
|
required []QueryMask
|
|
handler handler
|
|
}
|
|
|
|
func newRouter() *router {
|
|
selectRouter := &router{
|
|
direct: make(map[QueryMask]handler),
|
|
}
|
|
|
|
selectRouter.addFilter(
|
|
NewQueryMask(
|
|
SelectPartID|SelectPartStar|SelectPartField|SelectPartFields,
|
|
FromPartTable,
|
|
WherePartFieldCondition|WherePartMultiFieldCondition|WherePartIDCondition,
|
|
0,
|
|
0,
|
|
),
|
|
[]QueryMask{},
|
|
handlerSelectFieldsFromTableWhere{},
|
|
)
|
|
////
|
|
selectRouter.addFilter(
|
|
NewQueryMask(
|
|
SelectPartDistinct|SelectPartField,
|
|
FromPartTable,
|
|
WherePartFieldCondition|WherePartMultiFieldCondition,
|
|
0,
|
|
0,
|
|
),
|
|
[]QueryMask{},
|
|
handlerSelectDistinctFromTable{},
|
|
)
|
|
selectRouter.addRoute("select distinct fld from tbl", handlerSelectDistinctFromTable{})
|
|
////
|
|
selectRouter.addFilter(
|
|
NewQueryMask(
|
|
SelectPartCountStar|SelectPartCountField|SelectPartCountDistinctField,
|
|
FromPartTable,
|
|
WherePartFieldCondition|WherePartMultiFieldCondition|WherePartIDCondition,
|
|
0,
|
|
0,
|
|
),
|
|
[]QueryMask{},
|
|
handlerSelectCountFromTableWhere{},
|
|
)
|
|
////
|
|
selectRouter.addFilter(
|
|
NewQueryMask(
|
|
SelectPartMinField|SelectPartMaxField|SelectPartSumField|SelectPartAvgField,
|
|
FromPartTable,
|
|
WherePartFieldCondition|WherePartMultiFieldCondition|WherePartIDCondition,
|
|
0,
|
|
0,
|
|
),
|
|
[]QueryMask{},
|
|
handlerSelectFuncFromTableWhere{},
|
|
)
|
|
////
|
|
groupByOptional := NewQueryMask(
|
|
SelectPartField|SelectPartFields|SelectPartCountStar|SelectPartSumField,
|
|
FromPartTable,
|
|
WherePartFieldCondition|WherePartMultiFieldCondition,
|
|
GroupByPartField|GroupByPartFields,
|
|
HavingPartCondition,
|
|
)
|
|
selectRouter.addFilter(
|
|
groupByOptional,
|
|
[]QueryMask{NewQueryMask(0, 0, 0, GroupByPartField, 0)},
|
|
handlerSelectGroupBy{},
|
|
)
|
|
selectRouter.addFilter(
|
|
groupByOptional,
|
|
[]QueryMask{NewQueryMask(0, 0, 0, GroupByPartFields, 0)},
|
|
handlerSelectGroupBy{},
|
|
)
|
|
selectRouter.addRoute("select fld, count(fld) from tbl group by fld", handlerSelectGroupBy{})
|
|
selectRouter.addRoute("select fld1, count(fld1) from tbl where fld2=1 group by fld1", handlerSelectGroupBy{})
|
|
|
|
selectRouter.addRoute("select count(*) from tbl1 INNER JOIN tbl2 ON tbl1._id = tbl2.bsi", handlerSelectJoin{})
|
|
selectRouter.addRoute("select count(*) from tbl1 INNER JOIN tbl2 ON tbl1._id = tbl2.bsi where fld1=1", handlerSelectJoin{})
|
|
selectRouter.addRoute("select count(*) from tbl1 INNER JOIN tbl2 ON tbl1._id = tbl2.bsi where fld1=1 and fld2=2", handlerSelectJoin{})
|
|
selectRouter.addRoute("select _id from tbl1 INNER JOIN tbl2 ON tbl1._id = tbl2.bsi", handlerSelectJoin{})
|
|
selectRouter.addRoute("select _id from tbl1 INNER JOIN tbl2 ON tbl1._id = tbl2.bsi where fld1=1", handlerSelectJoin{})
|
|
selectRouter.addRoute("select _id from tbl1 INNER JOIN tbl2 ON tbl1._id = tbl2.bsi where fld1=1 and fld2=2", handlerSelectJoin{})
|
|
|
|
return selectRouter
|
|
}
|
|
|
|
func (r *router) addRoute(sql string, handler handler) {
|
|
r.direct[MustGenerateMask(sql)] = handler
|
|
}
|
|
|
|
func (r *router) addFilter(opt QueryMask, req []QueryMask, handler handler) {
|
|
mf := maskFilter{
|
|
optional: opt,
|
|
required: req,
|
|
handler: handler,
|
|
}
|
|
r.filters = append(r.filters, mf)
|
|
}
|
|
|
|
func (r *router) handler(qm QueryMask) handler {
|
|
// First, check for a direct mapping.
|
|
// Zero out the orderBy and limit mask, because
|
|
// those are not specific to the query processing.
|
|
zm := QueryMask{
|
|
SelectMask: qm.SelectMask,
|
|
FromMask: qm.FromMask,
|
|
WhereMask: qm.WhereMask,
|
|
GroupByMask: qm.GroupByMask,
|
|
HavingMask: qm.HavingMask,
|
|
}
|
|
if h, ok := r.direct[zm]; ok {
|
|
return h
|
|
}
|
|
for _, mf := range r.filters {
|
|
if applyMaskFilter(&qm, mf) {
|
|
return mf.handler
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// applyMaskFilter returns true if m passes the filter mf.
|
|
// Note: only certain query parts are included; namely,
|
|
// the orderBy and limit masks are not applied to the
|
|
// filter. A mask can satisfy any part of the optional
|
|
// filter to pass through, but it MUST satisfy all parts
|
|
// of the required filter.
|
|
func applyMaskFilter(m *QueryMask, mf maskFilter) bool {
|
|
if !m.ApplyFilter(mf.optional) {
|
|
return false
|
|
}
|
|
for _, req := range mf.required {
|
|
if m.SelectMask&req.SelectMask != req.SelectMask {
|
|
return false
|
|
}
|
|
if m.FromMask&req.FromMask != req.FromMask {
|
|
return false
|
|
}
|
|
if m.WhereMask&req.WhereMask != req.WhereMask {
|
|
return false
|
|
}
|
|
if m.GroupByMask&req.GroupByMask != req.GroupByMask {
|
|
return false
|
|
}
|
|
if m.HavingMask&req.HavingMask != req.HavingMask {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|