Ejemplo n.º 1
0
func (b *Backend) filterItem(info *db.ModelInfo, item *reflector.Reflector, filter Expression) (bool, apperror.Error) {
	switch f := filter.(type) {
	case *AndExpr:
		// Check each filter.
		for _, e := range f.Expressions() {
			flag, err := b.filterItem(info, item, e)
			if err != nil {
				return false, err
			} else if !flag {
				// One filter does not match, so return false.
				return false, nil
			}
		}
		// All filters matched, we can return true.
		return true, nil

	case *OrExpr:
		// Check each filter.
		for _, e := range f.Expressions() {
			flag, err := b.filterItem(info, item, e)
			if err != nil {
				return false, err
			} else if flag {
				// One match is enough, so return true.
				return true, nil
			}
		}
		// No filters matched, so return false.
		return false, nil

	case *NotExpr:
		// Reverse nested filter.
		flag, err := b.filterItem(info, item, f.Not())
		if err != nil {
			return false, err
		} else {
			return !flag, nil
		}

	case FilterExpression:
		field := f.Field()

		fieldName := ""

		if id, ok := field.(*IdentifierExpr); ok {
			fieldName = id.Identifier()
		} else if id, ok := field.(*ColFieldIdentifierExpr); ok {
			if id.Collection() != info.Collection() {
				return false, apperror.New("unsupported_filter", fmt.Sprint("The memory backend does not support filtering with joined collections"))
			}
			fieldName = id.Field()
		} else {
			return false, apperror.New("unsupported_filter", fmt.Sprintf("The memory backend does not support filtering with custom field expressions"))
		}

		attr := info.FindAttribute(fieldName)
		if attr == nil {
			return false, apperror.New("invalid_filter", fmt.Sprintf("Invalid filter for inexistant field %v", fieldName))
		}

		operator := f.Operator()

		var clauseValue interface{}

		if valExpr, ok := f.Clause().(*ValueExpr); ok {
			clauseValue = valExpr.Value()
		} else {
			return false, apperror.New("unsupported_filter_clause", fmt.Sprintf("The memory backend does not support filtering with custom clause expressions"))
		}

		if info.StructName() != "" {
			b.Logger().Infof("filtering item with %v %v %v", fieldName, operator, clauseValue)
			s, err := item.Struct()
			if err != nil {
				return false, apperror.Wrap(err, "invalid_model_error")
			}
			flag, err := s.Field(attr.Name()).CompareTo(clauseValue, operator)
			if err != nil {
				return false, apperror.Wrap(err, "compare_error")
			}
			return flag, nil
		} else {
			// Assume a map.
			if !item.IsMap() {
				return false, apperror.New("filter_invalid_model", "Could not filter because model value is neither struct nor map.")
			}
			flag, err := reflector.R(item.Value().MapIndex(reflect.ValueOf(attr.BackendName()))).CompareTo(clauseValue, operator)
			if err != nil {
				return false, apperror.Wrap(err, "compare_error")
			}
			return flag, nil
		}

	default:
		b.Logger().Panicf("Unhandled filter expression: %v", reflect.TypeOf(filter))
	}

	return false, nil
}