mirror of https://github.com/perkeep/perkeep.git
search: PermanodeConstraint.Time time constraint, 'before:' and 'after:' operators
Work in progress, but works enough to commit now. Determing the time of things has many TODOs, and there's some performance work to be done (although it still appears to be instant... it just uses more CPU than it should) Change-Id: I4b04b5805353dfbde0b841a3a557fd0b7c297780
This commit is contained in:
parent
7fcd2e1807
commit
a576379cb5
|
@ -659,6 +659,60 @@ func (c *Corpus) isDeletedLocked(br blob.Ref) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// PermanodeTimeLocked returns the time of the content in permanode.
|
||||
func (c *Corpus) PermanodeTimeLocked(pn blob.Ref) (t time.Time, ok bool) {
|
||||
// TODO(bradfitz): keep this time property cached on the permanode / files
|
||||
|
||||
// TODO(bradfitz): finish implmenting all these
|
||||
|
||||
// Priorities:
|
||||
// -- Permanode explicit "camliTime" property
|
||||
// -- EXIF GPS time
|
||||
// -- Exif camera time
|
||||
// -- File time
|
||||
// -- File modtime
|
||||
// -- camliContent claim set time
|
||||
ccRef, ccTime, ok := c.pnCamliContentLocked(pn)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
fi, ok := c.files[ccRef]
|
||||
if ok {
|
||||
if fi.Time != nil {
|
||||
return time.Time(*fi.Time), true
|
||||
}
|
||||
if fi.ModTime != nil {
|
||||
return time.Time(*fi.ModTime), true
|
||||
}
|
||||
}
|
||||
return ccTime, true
|
||||
}
|
||||
|
||||
func (c *Corpus) pnCamliContentLocked(pn blob.Ref) (cc blob.Ref, t time.Time, ok bool) {
|
||||
// TODO(bradfitz): keep this property cached
|
||||
pm, ok := c.permanodes[pn]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
for _, cl := range pm.Claims {
|
||||
if cl.Attr != "camliContent" {
|
||||
continue
|
||||
}
|
||||
// TODO: pass down the 'PermanodeConstraint.At' parameter, and then do: if cl.Date.After(at) { continue }
|
||||
switch cl.Type {
|
||||
case string(schema.DelAttributeClaim):
|
||||
cc = blob.Ref{}
|
||||
t = time.Time{}
|
||||
case string(schema.SetAttributeClaim):
|
||||
cc = blob.ParseOrZero(cl.Value)
|
||||
t = cl.Date
|
||||
}
|
||||
}
|
||||
return cc, t, cc.Valid()
|
||||
|
||||
}
|
||||
|
||||
// PermanodeModtime returns the latest modification time of the given
|
||||
// permanode.
|
||||
//
|
||||
|
|
|
@ -23,9 +23,11 @@ import (
|
|||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"camlistore.org/pkg/context"
|
||||
"camlistore.org/pkg/geocode"
|
||||
"camlistore.org/pkg/types"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -183,6 +185,36 @@ func parseExpression(ctx *context.Context, exp string) (*SearchQuery, error) {
|
|||
})
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(word, "before:") || strings.HasPrefix(word, "after:") {
|
||||
before := false
|
||||
when := ""
|
||||
if strings.HasPrefix(word, "before:") {
|
||||
before = true
|
||||
when = strings.TrimPrefix(word, "before:")
|
||||
} else {
|
||||
when = strings.TrimPrefix(word, "after:")
|
||||
}
|
||||
base := "0000-01-01T00:00:00Z"
|
||||
if len(when) < len(base) {
|
||||
when += base[len(when):]
|
||||
}
|
||||
t, err := time.Parse(time.RFC3339, when)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tc := &TimeConstraint{}
|
||||
if before {
|
||||
tc.Before = types.Time3339(t)
|
||||
} else {
|
||||
tc.After = types.Time3339(t)
|
||||
}
|
||||
and(&Constraint{
|
||||
Permanode: &PermanodeConstraint{
|
||||
Time: tc,
|
||||
},
|
||||
})
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(word, "loc:") {
|
||||
where := strings.TrimPrefix(word, "loc:")
|
||||
rects, err := geocode.Lookup(ctx, where)
|
||||
|
|
|
@ -521,6 +521,12 @@ type PermanodeConstraint struct {
|
|||
// ModTime optionally matches on the last modtime of the permanode.
|
||||
ModTime *TimeConstraint `json:"modTime,omitempty"`
|
||||
|
||||
// Time optionally matches the permanode's time. A Permanode
|
||||
// may not have a known time. If the permanode does not have a
|
||||
// known time, one may be guessed if the top-level search
|
||||
// parameters request so.
|
||||
Time *TimeConstraint `json:"time,omitempty"`
|
||||
|
||||
// Attr optionally specifies the attribute to match.
|
||||
// e.g. "camliContent", "camliMember", "tag"
|
||||
// This is required if any of the items below are used.
|
||||
|
@ -1032,6 +1038,17 @@ func (c *PermanodeConstraint) blobMatches(s *search, br blob.Ref, bm camtypes.Bl
|
|||
}
|
||||
}
|
||||
|
||||
if c.Time != nil {
|
||||
if corpus != nil {
|
||||
t, ok := corpus.PermanodeTimeLocked(br)
|
||||
if !ok || !c.Time.timeMatches(t) {
|
||||
return false, nil
|
||||
}
|
||||
} else {
|
||||
panic("TODO: not yet supported")
|
||||
}
|
||||
}
|
||||
|
||||
if cc := c.Continue; cc != nil {
|
||||
if corpus == nil {
|
||||
// Requires an in-memory index for infinite
|
||||
|
|
Loading…
Reference in New Issue