             } else {
                 return Term(string: string)
             }
-        case .str, .strlen, .lcase, .ucase, .encode_for_uri, .datatype:
+        case .str, .strlen, .lcase, .ucase, .datatype, .encode_for_uri:
             try guardArity(terms.count, 1, stringFunction.rawValue)
             guard let string = terms[0] else { throw QueryError.evaluationError("Not all arguments are bound in \(stringFunction) call") }
             switch stringFunction {

    public func numericEvaluate(expression: Expression, result: TermResult) throws -> NumericValue {
        switch expression {
        case .aggregate(_):
            fatalError("cannot evaluate an aggregate expression without a query context")
        case .node(.bound(let term)):
            if let num = term.numeric {
                return num

                } else {
                    return Term(string: "")
                }
            case .strafter:
                guard pattern.value != "" else { return string }
                if let range = string.value.range(of: pattern.value) {
                    let suffix = String(string.value[range.upperBound...])
