Azure / azure-sdk-for-rust

This repository is for the active development of the Azure SDK for Rust. For consumers of the SDK we recommend visiting Docs.rs and looking up the docs for any of libraries in the SDK.
MIT License
707 stars 246 forks source link

Using aggregate functions in query doesn't seem to work. #946

Open deadshot465 opened 2 years ago

deadshot465 commented 2 years ago

So I was trying to do this yesterday:

let query = Query::new(format!("SELECT MAX(u.Id) FROM {} u", "Users"));
let documents: Option<Vec<HashMap<String, i32>>> = collection
    .query_documents(query)
    .query_cross_partition(true)
    .into_stream::<HashMap<String, i32>>()
    .collect::<Vec<_>>()
    .await
    .into_iter()
    .collect::<Result<Vec<_>, _>>()
    .map_err(|e| log::error!("Failed to retrieve document: {}", e))
    .ok()
    .and_then(|result| result.first().cloned())
    .map(|response| {
        response
            .results
            .into_iter()
            .map(|data| match data {
                QueryResult::Document(doc) => doc.result,
                QueryResult::Raw(raw) => raw,
            })
            .collect()
    });

The request failed and the logs only showed

[2022-07-19T17:51:59Z ERROR azure_core::policies::retry_policies::retry_policy] server returned error status which will not be retried: 400 Bad Request
[2022-07-19T17:51:59Z ERROR my_actix::shared::util] Failed to retrieve document: server returned error status which will not be retried

But the query worked fine in Azure portal when I created a new SQL query against the container. I tried searching in the docs, but I couldn't seem to find other functions that accept queries. Digging in Microsoft docs, I also found this here:

If the operation is performed against a specific resource then the value is the link to that resource. Examples:

For Get Database use: dbs/{databaseId}
For Get Document use: dbs/{databaseId}/colls/{containerId}/docs/{docId}
If the operation is performed against a set of resources (List, Create, Query) then the value is the link of the parent resource. Examples:

For Create Document use: dbs/{databaseId}/colls/{containerId}
For Create Stored Procedure use: dbs/{databaseId}/colls/{containerId}
For Create a Container use: dbs/{databaseId}
For Create Database use: "" -> an empty string since Databases do not have a parent resource

But the logs showed that the endpoint being requested was https://<my-db-account>.documents.azure.com/dbs/<my-db-name>/colls/Users/docs, which doesn't seem to be the right endpoint?

It led me to think if the 400 Bad Request was caused by this:

The request body should be a valid JSON document containing the SQL query and parameters. If the input is malformed or invalid SQL syntax, the operation with fails with a 400 Bad Request error.

You will also get a 400 bad request if a [query cannot be served by the gateway](https://docs.microsoft.com/en-us/rest/api/cosmos-db/querying-cosmosdb-resources-using-the-rest-api#queries-that-cannot-be-served-by-gateway).

Is it a bug, or the library currently doesn't support using aggregate functions in queries, or I'm calling an incorrect function?

rylev commented 2 years ago

We can certainly do a better job showing nice error messages, but I'll address the direct issue. You are likely getting a 400 due to trying to query across continuations. I believe this is due to the use of "max" in your query. I'm not familiar enough with Cosmos DBs querying engine to know what the work around is here.

I could not find out how other SDKs are currently handling this, but perhaps @heaths has some insight.

heaths commented 2 years ago

By design, we try to avoid extra client-side validation and, by extension, assumption of error causes unless obvious. Thus, we pass the service errors straight through. Perhaps improving the error e.g., making it actionable, is best done by the service themselves.

rylev commented 2 years ago

@heaths interestingly the error message says that this should be handled by the client:

This is a first chance (internal) exception that all newer clients will know how to handle gracefully. This exception is traced, but unless you see it bubble up as an exception (which only happens on older SDK clients)

Do you know what that refers to?

heaths commented 2 years ago

I didn't see that in the error above, but it is in the page linked (which shouldn't refer to the "en-us" locale, but that's an entirely different issue). I don't know anything about the Cosmos service.

Adding codeowners from the Azure SDK for .NET repo: @pjohari-ms @MehaKaushik @shurd @anfeldma-ms @zfoster @kushagraThapar

Can anyone shed some light on what this error means and if/how we should better represent it? Ideally, behavior here should match what we do in other languages for Azure SDK but I have no insight into the Cosmos DB SDK.