Repository: edgedb/edgedb

Issue:
Rename cardinality N/A to consistent NO_RESULT
Got this unclear error `cardinality N/A cannot be requested`. Also it looks like there are few other instances in `edgecon.pyx`. Should everywhere be NO_RESULT as we document in RST files.


Discussion:
@aeros, you can take this one, if you're still looking for a trivial task.
Thanks, I'd be willing to help with this.
@aeros, what's your status? Is the issue description clear enough (well, I've written it just as a note to myself, so it's not detailed enough)? Any help needed?
@tailhook I was out of town when I responded to the @ mention, I just got back home earlier today. I should have time to work on it this week and will let you know if I have any questions. Thanks for checking (:
@tailhook I was doing a bit of investigation into this to determine all of the different areas where the cardinality result should be changed from `NOT_APPLICABLE` to `NO_RESULT`.

I believe the primary area to change is here: https://github.com/edgedb/edgedb/blob/570375f163d08e132b98e8b78f62f2105710aff5/edb/server/compiler/enums.py#L34-L46
and everything that currently references `ResultCardinality.NOT_APPLICABLE` to `ResultCardinality.NO_RESULT`; as well as changing:

https://github.com/edgedb/edgedb/blob/570375f163d08e132b98e8b78f62f2105710aff5/edb/server/mng_port/edgecon.pyx#L749-L756

to return `CARD_NO_RESULT` or `CARD_NONE` (which would be an alias to the new `ResultCardinality.NO_RESULT`, similar to the above `CARD_ONE` and `CARD_MANY`) instead of raising the `BinaryProtocolError`. Is this correct?

Alternatively, did you simply mean to change the text of the error message from `cardinality N/A cannot be requested` to `cardinality NO_RESULT cannot be requested`? 

The scope of this issue isn't 100% clear to me, since you mentioned "Should *everywhere* be NO_RESULT as we document in RST files", but the first sentence seemed to indicate that this issue is primarily based around the error message. 
Yes, I meant both `ResultCardinality` and the error message.

But I'm not sure why we might want to turn an exception to return value. We don't accept cardinality of NO_RESULT from a client, we can only return it in `Describe` message. So exception is fine here, just need to have a consistent title for this variant everywhere.
> Yes, I meant both ResultCardinality and the error message.

Okay, thanks for clarifying.

> But I'm not sure why we might want to turn an exception to return value. We don't accept cardinality of NO_RESULT from a client, we can only return it in Describe message. So exception is fine here, just need to have a consistent title for this variant everywhere.

Ah, that makes sense. I'm not very familiar with the logic in `edgecon.pyx`, this is actually my first time looking at that directory (`edb/server/mng_port/`). The purpose behind the exception wasn't clear to me when I wrote the above comment.

Just to better to understand it: what sort of input from the client would cause this exception to be raised? Specifically, how exactly would the client submit a cardinality of NO_RESULT in the first place? I haven't personally encountered this error message before.

Resolving patch:
diff --git a/edb/server/compiler/compiler.py b/edb/server/compiler/compiler.py
--- a/edb/server/compiler/compiler.py
+++ b/edb/server/compiler/compiler.py
@@ -885,7 +885,7 @@ def _compile(self, *,
         # That means that the returned QueryUnit has to have the in/out codec
         # information, correctly inferred "singleton_result" field etc.
         single_stmt_mode = ctx.stmt_mode is enums.CompileStatementMode.SINGLE
-        default_cardinality = enums.ResultCardinality.NOT_APPLICABLE
+        default_cardinality = enums.ResultCardinality.NO_RESULT
 
         eql = eql.decode()
 
@@ -1017,7 +1017,7 @@ def _compile(self, *,
         for unit in units:  # pragma: no cover
             # Sanity checks
             na_cardinality = (
-                unit.cardinality is enums.ResultCardinality.NOT_APPLICABLE
+                unit.cardinality is enums.ResultCardinality.NO_RESULT
             )
             if unit.cacheable and (unit.config_ops or unit.modaliases):
                 raise errors.InternalServerError(
diff --git a/edb/server/compiler/dbstate.py b/edb/server/compiler/dbstate.py
--- a/edb/server/compiler/dbstate.py
+++ b/edb/server/compiler/dbstate.py
@@ -150,10 +150,10 @@ class QueryUnit:
     # True if it is safe to cache this unit.
     cacheable: bool = False
 
-    # Cardinality of the result set.  Set to NOT_APPLICABLE if the
+    # Cardinality of the result set.  Set to NO_RESULT if the
     # unit represents multiple queries compiled as one script.
     cardinality: enums.ResultCardinality = \
-        enums.ResultCardinality.NOT_APPLICABLE
+        enums.ResultCardinality.NO_RESULT
 
     out_type_data: bytes = sertypes.NULL_TYPE_DESC
     out_type_id: bytes = sertypes.NULL_TYPE_ID
diff --git a/edb/server/compiler/enums.py b/edb/server/compiler/enums.py
--- a/edb/server/compiler/enums.py
+++ b/edb/server/compiler/enums.py
@@ -43,7 +43,7 @@ class ResultCardinality(strenum.StrEnum):
     # * the query is a command like CONFIGURE that
     #   does not return any data;
     # * the query is composed of multiple queries.
-    NOT_APPLICABLE = 'N/A'
+    NO_RESULT = 'NO_RESULT'
 
 
 class Capability(enum.Flag):


Test patch: