func (q *PkgQuery) Query(list PackageCatalog) (result *PackageList) {
	return list.SearchByKey(q.Arch, q.Pkg, q.Version)
}
Query looks up specific package
package deb
import (
	"fmt"
	"path/filepath"
	"regexp"
	"strings"
)
type PackageLike interface {
	GetField(string) string
	MatchesDependency(Dependency) bool
	MatchesArchitecture(string) bool
	GetName() string
	GetVersion() string
	GetArchitecture() string
}
type PackageCatalog interface {
	Scan(q PackageQuery) (result *PackageList)
	Search(dep Dependency, allMatches bool) (searchResults []*Package)
	SearchSupported() bool
	SearchByKey(arch, name, version string) (result *PackageList)
}
type PackageQuery interface {
	Matches(pkg PackageLike) bool
	Fast(list PackageCatalog) bool
	Query(list PackageCatalog) *PackageList
	String() string
}
type OrQuery struct {
	L, R PackageQuery
}
type AndQuery struct {
	L, R PackageQuery
}
type NotQuery struct {
	Q PackageQuery
}
type FieldQuery struct {
	Field    string
	Relation int
	Value    string
	Regexp   *regexp.Regexp `codec:"-"`
}
type PkgQuery struct {
	Pkg     string
	Version string
	Arch    string
}
type DependencyQuery struct {
	Dep Dependency
}
type MatchAllQuery struct{}
func (q *OrQuery) Matches(pkg PackageLike) bool {
	return q.L.Matches(pkg) || q.R.Matches(pkg)
}
func (q *OrQuery) Fast(list PackageCatalog) bool {
	return q.L.Fast(list) && q.R.Fast(list)
}
func (q *OrQuery) Query(list PackageCatalog) (result *PackageList) {
	if q.Fast(list) {
		result = q.L.Query(list)
		result.Append(q.R.Query(list))
	} else {
		result = list.Scan(q)
	}
	return
}
func (q *OrQuery) String() string {
	return fmt.Sprintf("(%s) | (%s)", q.L, q.R)
}
func (q *AndQuery) Matches(pkg PackageLike) bool {
	return q.L.Matches(pkg) && q.R.Matches(pkg)
}
func (q *AndQuery) Fast(list PackageCatalog) bool {
	return q.L.Fast(list) || q.R.Fast(list)
}
func (q *AndQuery) Query(list PackageCatalog) (result *PackageList) {
	if !q.Fast(list) {
		result = list.Scan(q)
	} else {
		if q.L.Fast(list) {
			result = q.L.Query(list)
			result = result.Scan(q.R)
		} else {
			result = q.R.Query(list)
			result = result.Scan(q.L)
		}
	}
	return
}
func (q *AndQuery) String() string {
	return fmt.Sprintf("(%s), (%s)", q.L, q.R)
}
func (q *NotQuery) Matches(pkg PackageLike) bool {
	return !q.Q.Matches(pkg)
}
func (q *NotQuery) Fast(list PackageCatalog) bool {
	return false
}
func (q *NotQuery) Query(list PackageCatalog) (result *PackageList) {
	result = list.Scan(q)
	return
}
func (q *NotQuery) String() string {
	return fmt.Sprintf("!(%s)", q.Q)
}
func (q *FieldQuery) Matches(pkg PackageLike) bool {
	if q.Field == "$Version" {
		return pkg.MatchesDependency(Dependency{Pkg: pkg.GetName(), Relation: q.Relation, Version: q.Value, Regexp: q.Regexp})
	}
	if q.Field == "$Architecture" && q.Relation == VersionEqual {
		return pkg.MatchesArchitecture(q.Value)
	}
	field := pkg.GetField(q.Field)
	switch q.Relation {
	case VersionDontCare:
		return field != ""
	case VersionEqual:
		return field == q.Value
	case VersionGreater:
		return field > q.Value
	case VersionGreaterOrEqual:
		return field >= q.Value
	case VersionLess:
		return field < q.Value
	case VersionLessOrEqual:
		return field <= q.Value
	case VersionPatternMatch:
		matched, err := filepath.Match(q.Value, field)
		return err == nil && matched
	case VersionRegexp:
		if q.Regexp == nil {
			q.Regexp = regexp.MustCompile(q.Value)
		}
		return q.Regexp.FindStringIndex(field) != nil
	}
	panic("unknown relation")
}
func (q *FieldQuery) Query(list PackageCatalog) (result *PackageList) {
	result = list.Scan(q)
	return
}
func (q *FieldQuery) Fast(list PackageCatalog) bool {
	return false
}
func (q *FieldQuery) String() string {
	escape := func(val string) string {
		if strings.ContainsAny(val, "()|,!{} \t\n") {
			return "'" + strings.Replace(strings.Replace(val, "\\", "\\\\", -1), "'", "\\'", -1) + "'"
		}
		return val
	}
	var op string
	switch q.Relation {
	case VersionEqual:
		op = "="
	case VersionGreater:
		op = ">>"
	case VersionLess:
		op = "<<"
	case VersionRegexp:
		op = "~"
	case VersionPatternMatch:
		op = "%"
	case VersionGreaterOrEqual:
		op = ">="
	case VersionLessOrEqual:
		op = "<="
	}
	return fmt.Sprintf("%s (%s %s)", escape(q.Field), op, escape(q.Value))
}
func (q *DependencyQuery) Matches(pkg PackageLike) bool {
	return pkg.MatchesDependency(q.Dep)
}
func (q *DependencyQuery) Fast(list PackageCatalog) bool {
	return list.SearchSupported()
}
func (q *DependencyQuery) Query(list PackageCatalog) (result *PackageList) {
	if q.Fast(list) {
		result = NewPackageList()
		for _, pkg := range list.Search(q.Dep, true) {
			result.Add(pkg)
		}
	} else {
		result = list.Scan(q)
	}
	return
}
func (q *DependencyQuery) String() string {
	return q.Dep.String()
}
func (q *PkgQuery) Matches(pkg PackageLike) bool {
	return pkg.GetName() == q.Pkg && pkg.GetVersion() == q.Version && pkg.GetArchitecture() == q.Arch
}
func (q *PkgQuery) Fast(list PackageCatalog) bool {
	return true
}