Example #1
0
func (l location) Predicate(ctx context.Context, args []string) (*Constraint, error) {
	where := args[0]
	rects, err := geocode.Lookup(ctx, where)
	if err != nil {
		return nil, err
	}
	if len(rects) == 0 {
		return nil, fmt.Errorf("No location found for %q", where)
	}
	var c *Constraint
	for i, rect := range rects {
		loc := &LocationConstraint{
			West:  rect.SouthWest.Long,
			East:  rect.NorthEast.Long,
			North: rect.NorthEast.Lat,
			South: rect.SouthWest.Lat,
		}
		permLoc := &Constraint{
			Permanode: &PermanodeConstraint{
				Location: loc,
			},
		}
		if i == 0 {
			c = permLoc
		} else {
			c = orConst(c, permLoc)
		}
	}
	return c, nil
}
Example #2
0
func parseLocationAtom(ctx *context.Context, word string) (*Constraint, error) {
	if strings.HasPrefix(word, "loc:") {
		where := strings.TrimPrefix(word, "loc:")
		rects, err := geocode.Lookup(ctx, where)
		if err != nil {
			return nil, err
		}
		if len(rects) == 0 {
			return nil, fmt.Errorf("No location found for %q", where)
		}
		var c *Constraint
		for i, rect := range rects {
			loc := &LocationConstraint{
				West:  rect.SouthWest.Long,
				East:  rect.NorthEast.Long,
				North: rect.NorthEast.Lat,
				South: rect.SouthWest.Lat,
			}
			fileLoc := permOfFile(&FileConstraint{
				IsImage:  true,
				Location: loc,
			})
			permLoc := &Constraint{
				Permanode: &PermanodeConstraint{
					Location: loc,
				},
			}
			rectConstraint := orConst(fileLoc, permLoc)
			if i == 0 {
				c = rectConstraint
			} else {
				c = orConst(c, rectConstraint)
			}
		}
		return c, nil
	}
	if word == "has:location" {
		c := permOfFile(&FileConstraint{
			IsImage: true,
			Location: &LocationConstraint{
				Any: true,
			},
		})
		return c, nil
	}

	return nil, errors.New(fmt.Sprintf("Not an location-atom: %v", word))
}
Example #3
0
// parseExpression parses a search expression (e.g. "tag:funny
// near:portland") and returns a SearchQuery for that search text. The
// Constraint field will always be set. The Limit and Sort may also be
// set.
func parseExpression(ctx *context.Context, exp string) (*SearchQuery, error) {
	base := &Constraint{
		Permanode: &PermanodeConstraint{
			SkipHidden: true,
		},
	}
	sq := &SearchQuery{
		Constraint: base,
	}

	exp = strings.TrimSpace(exp)
	if exp == "" {
		return sq, nil
	}

	andNot := false // whether the next and(x) is really a and(!x)
	and := func(c *Constraint) {
		old := sq.Constraint
		if andNot {
			c = &Constraint{
				Logical: &LogicalConstraint{
					Op: "not",
					A:  c,
				},
			}
		}
		sq.Constraint = &Constraint{
			Logical: &LogicalConstraint{
				Op: "and",
				A:  old,
				B:  c,
			},
		}
	}
	permOfFile := func(fc *FileConstraint) *Constraint {
		return &Constraint{
			Permanode: &PermanodeConstraint{
				Attr:       "camliContent",
				ValueInSet: &Constraint{File: fc},
			},
		}
	}
	orConst := func(a, b *Constraint) *Constraint {
		return &Constraint{
			Logical: &LogicalConstraint{
				Op: "or",
				A:  a,
				B:  b,
			},
		}
	}
	andFile := func(fc *FileConstraint) {
		and(permOfFile(fc))
	}
	andWHRatio := func(fc *FloatConstraint) {
		andFile(&FileConstraint{
			IsImage: true,
			WHRatio: fc,
		})
	}

	words := strings.Fields(exp)
	for _, word := range words {
		andNot = false
		if strings.HasPrefix(word, "-") {
			andNot = true
			word = word[1:]
		}
		if m := tagExpr.FindStringSubmatch(word); m != nil {
			and(&Constraint{
				Permanode: &PermanodeConstraint{
					Attr:       "tag",
					SkipHidden: true,
					Value:      m[1],
				},
			})
			continue
		}
		if m := titleExpr.FindStringSubmatch(word); m != nil {
			and(&Constraint{
				Permanode: &PermanodeConstraint{
					Attr:       "title",
					SkipHidden: true,
					ValueMatches: &StringConstraint{
						Contains:        m[1],
						CaseInsensitive: true,
					},
				},
			})
			continue
		}
		if word == "is:image" {
			and(&Constraint{
				Permanode: &PermanodeConstraint{
					Attr: "camliContent",
					ValueInSet: &Constraint{
						File: &FileConstraint{
							IsImage: true,
						},
					},
				},
			})
			continue
		}
		if word == "is:landscape" {
			andWHRatio(&FloatConstraint{Min: 1.0})
			continue
		}
		if word == "is:portrait" {
			andWHRatio(&FloatConstraint{Max: 1.0})
			continue
		}
		if word == "is:pano" {
			andWHRatio(&FloatConstraint{Min: 1.6})
			continue
		}
		if word == "has:location" {
			andFile(&FileConstraint{
				IsImage: true,
				Location: &LocationConstraint{
					Any: true,
				},
			})
			continue
		}
		if strings.HasPrefix(word, "format:") {
			andFile(&FileConstraint{
				MIMEType: &StringConstraint{
					Equals: mimeFromFormat(strings.TrimPrefix(word, "format:")),
				},
			})
			continue
		}
		if strings.HasPrefix(word, "width:") {
			m := whRangeExpr.FindStringSubmatch(strings.TrimPrefix(word, "width:"))
			if m == nil {
				return nil, errors.New("bogus width range")
			}
			andFile(&FileConstraint{
				IsImage: true,
				Width:   whIntConstraint(m[1], m[2]),
			})
			continue
		}
		if strings.HasPrefix(word, "height:") {
			m := whRangeExpr.FindStringSubmatch(strings.TrimPrefix(word, "height:"))
			if m == nil {
				return nil, errors.New("bogus height range")
			}
			andFile(&FileConstraint{
				IsImage: true,
				Height:  whIntConstraint(m[1], m[2]),
			})
			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)
			if err != nil {
				return nil, err
			}
			if len(rects) == 0 {
				return nil, fmt.Errorf("No location found for %q", where)
			}
			var locConstraint *Constraint
			for i, rect := range rects {
				rectConstraint := permOfFile(&FileConstraint{
					IsImage: true,
					Location: &LocationConstraint{
						West:  rect.SouthWest.Long,
						East:  rect.NorthEast.Long,
						North: rect.NorthEast.Lat,
						South: rect.SouthWest.Lat,
					},
				})
				if i == 0 {
					locConstraint = rectConstraint
				} else {
					locConstraint = orConst(locConstraint, rectConstraint)
				}
			}
			and(locConstraint)
			continue
		}
		log.Printf("Unknown search expression word %q", word)
		// TODO: finish. better tokenization. non-operator tokens
		// are text searches, etc.
	}

	return sq, nil
}