New common interface for PackgeCollection & PackageList: PackageCatalog. #80

This commit is contained in:
Andrey Smirnov
2014-08-28 19:41:30 +04:00
parent ed03a7c69e
commit 608870265c
3 changed files with 105 additions and 31 deletions
+18
View File
@@ -41,6 +41,7 @@ type PackageList struct {
// Verify interface // Verify interface
var ( var (
_ sort.Interface = &PackageList{} _ sort.Interface = &PackageList{}
_ PackageCatalog = &PackageList{}
) )
// NewPackageList creates empty package list // NewPackageList creates empty package list
@@ -356,6 +357,23 @@ func (l *PackageList) Scan(q PackageQuery) (result *PackageList) {
return return
} }
// SearchSupported returns true for PackageList
func (l *PackageList) SearchSupported() bool {
return true
}
// SearchByKey looks up package by exact key reference
func (l *PackageList) SearchByKey(arch, name, version string) (result *PackageList) {
result = NewPackageList()
pkg := l.packages["P"+arch+" "+name+" "+version]
if pkg != nil {
result.Add(pkg)
}
return
}
// Search searches package index for specified package(s) using optimized queries // Search searches package index for specified package(s) using optimized queries
func (l *PackageList) Search(dep Dependency, allMatches bool) (searchResults []*Package) { func (l *PackageList) Search(dep Dependency, allMatches bool) (searchResults []*Package) {
if !l.indexed { if !l.indexed {
+51
View File
@@ -15,6 +15,11 @@ type PackageCollection struct {
codecHandle *codec.MsgpackHandle codecHandle *codec.MsgpackHandle
} }
// Verify interface
var (
_ PackageCatalog = &PackageCollection{}
)
// NewPackageCollection creates new PackageCollection and binds it to database // NewPackageCollection creates new PackageCollection and binds it to database
func NewPackageCollection(db database.Storage) *PackageCollection { func NewPackageCollection(db database.Storage) *PackageCollection {
return &PackageCollection{ return &PackageCollection{
@@ -237,3 +242,49 @@ func (collection *PackageCollection) DeleteByKey(key []byte) error {
} }
return nil return nil
} }
// Scan does full scan on all the packages
func (collection *PackageCollection) Scan(q PackageQuery) (result *PackageList) {
result = NewPackageList()
for _, key := range collection.db.KeysByPrefix([]byte("P")) {
pkg, err := collection.ByKey(key)
if err != nil {
panic(fmt.Sprintf("unable to load package: %s", err))
}
if q.Matches(pkg) {
result.Add(pkg)
}
}
return
}
// Search is not implemented
func (collection *PackageCollection) Search(dep Dependency, allMatches bool) (searchResults []*Package) {
panic("Not implemented")
}
// SearchSupported returns false
func (collection *PackageCollection) SearchSupported() bool {
return false
}
// SearchByKey finds package by exact key
func (collection *PackageCollection) SearchByKey(arch, name, version string) (result *PackageList) {
result = NewPackageList()
for _, key := range collection.db.KeysByPrefix([]byte(fmt.Sprintf("P%s %s %s", arch, name, version))) {
pkg, err := collection.ByKey(key)
if err != nil {
panic(fmt.Sprintf("unable to load package: %s", err))
}
if pkg.Architecture == arch && pkg.Name == name && pkg.Version == version {
result.Add(pkg)
}
}
return
}
+36 -31
View File
@@ -7,14 +7,22 @@ import (
"strings" "strings"
) )
// PackageCatalog is abstraction on top of PackageCollection and PackageList
type PackageCatalog interface {
Scan(q PackageQuery) (result *PackageList)
Search(dep Dependency, allMatches bool) (searchResults []*Package)
SearchSupported() bool
SearchByKey(arch, name, version string) (result *PackageList)
}
// PackageQuery is interface of predicate on Package // PackageQuery is interface of predicate on Package
type PackageQuery interface { type PackageQuery interface {
// Matches calculates match of condition against package // Matches calculates match of condition against package
Matches(pkg *Package) bool Matches(pkg *Package) bool
// Fast returns if search strategy is possible for this query // Fast returns if search strategy is possible for this query
Fast() bool Fast(list PackageCatalog) bool
// Query performs search on package list // Query performs search on package list
Query(list *PackageList) *PackageList Query(list PackageCatalog) *PackageList
// String interface // String interface
String() string String() string
} }
@@ -60,13 +68,13 @@ func (q *OrQuery) Matches(pkg *Package) bool {
} }
// Fast is true only if both parts are fast // Fast is true only if both parts are fast
func (q *OrQuery) Fast() bool { func (q *OrQuery) Fast(list PackageCatalog) bool {
return q.L.Fast() && q.R.Fast() return q.L.Fast(list) && q.R.Fast(list)
} }
// Query strategy depends on nodes // Query strategy depends on nodes
func (q *OrQuery) Query(list *PackageList) (result *PackageList) { func (q *OrQuery) Query(list PackageCatalog) (result *PackageList) {
if q.Fast() { if q.Fast(list) {
result = q.L.Query(list) result = q.L.Query(list)
result.Append(q.R.Query(list)) result.Append(q.R.Query(list))
} else { } else {
@@ -86,16 +94,16 @@ func (q *AndQuery) Matches(pkg *Package) bool {
} }
// Fast is true if any of the parts are fast // Fast is true if any of the parts are fast
func (q *AndQuery) Fast() bool { func (q *AndQuery) Fast(list PackageCatalog) bool {
return q.L.Fast() || q.R.Fast() return q.L.Fast(list) || q.R.Fast(list)
} }
// Query strategy depends on nodes // Query strategy depends on nodes
func (q *AndQuery) Query(list *PackageList) (result *PackageList) { func (q *AndQuery) Query(list PackageCatalog) (result *PackageList) {
if !q.Fast() { if !q.Fast(list) {
result = list.Scan(q) result = list.Scan(q)
} else { } else {
if q.L.Fast() { if q.L.Fast(list) {
result = q.L.Query(list) result = q.L.Query(list)
result = result.Scan(q.R) result = result.Scan(q.R)
} else { } else {
@@ -117,12 +125,12 @@ func (q *NotQuery) Matches(pkg *Package) bool {
} }
// Fast is false // Fast is false
func (q *NotQuery) Fast() bool { func (q *NotQuery) Fast(list PackageCatalog) bool {
return false return false
} }
// Query strategy is scan always // Query strategy is scan always
func (q *NotQuery) Query(list *PackageList) (result *PackageList) { func (q *NotQuery) Query(list PackageCatalog) (result *PackageList) {
result = list.Scan(q) result = list.Scan(q)
return return
} }
@@ -170,13 +178,13 @@ func (q *FieldQuery) Matches(pkg *Package) bool {
} }
// Query runs iteration through list // Query runs iteration through list
func (q *FieldQuery) Query(list *PackageList) (result *PackageList) { func (q *FieldQuery) Query(list PackageCatalog) (result *PackageList) {
result = list.Scan(q) result = list.Scan(q)
return return
} }
// Fast depends on the query // Fast depends on the query
func (q *FieldQuery) Fast() bool { func (q *FieldQuery) Fast(list PackageCatalog) bool {
return false return false
} }
@@ -215,15 +223,19 @@ func (q *DependencyQuery) Matches(pkg *Package) bool {
} }
// Fast is always true for dependency query // Fast is always true for dependency query
func (q *DependencyQuery) Fast() bool { func (q *DependencyQuery) Fast(list PackageCatalog) bool {
return true return list.SearchSupported()
} }
// Query runs PackageList.Search // Query runs PackageList.Search
func (q *DependencyQuery) Query(list *PackageList) (result *PackageList) { func (q *DependencyQuery) Query(list PackageCatalog) (result *PackageList) {
result = NewPackageList() if q.Fast(list) {
for _, pkg := range list.Search(q.Dep, true) { result = NewPackageList()
result.Add(pkg) for _, pkg := range list.Search(q.Dep, true) {
result.Add(pkg)
}
} else {
result = list.Scan(q)
} }
return return
@@ -240,20 +252,13 @@ func (q *PkgQuery) Matches(pkg *Package) bool {
} }
// Fast is always true for package query // Fast is always true for package query
func (q *PkgQuery) Fast() bool { func (q *PkgQuery) Fast(list PackageCatalog) bool {
return true return true
} }
// Query looks up specific package // Query looks up specific package
func (q *PkgQuery) Query(list *PackageList) (result *PackageList) { func (q *PkgQuery) Query(list PackageCatalog) (result *PackageList) {
result = NewPackageList() return list.SearchByKey(q.Arch, q.Pkg, q.Version)
pkg := list.packages["P"+q.Arch+" "+q.Pkg+" "+q.Version]
if pkg != nil {
result.Add(pkg)
}
return
} }
// String interface // String interface