edgedb-js icon indicating copy to clipboard operation
edgedb-js copied to clipboard

Allow the queries generator to statically analyze the query to ensure expressions are typed correctly and fail at generation time if not

Open jackfischer opened this issue 1 year ago • 6 comments

  • EdgeDB Version: 4.5
  • EdgeDB CLI Version: 4.1.0
  • OS Version: macos 13

Unsure if this is considered a bug or an FR but it caused a bug for us to slip into production basically breaking this expectation

Steps to Reproduce:

  1. Create an object type with a required property
Example {
  required name: str;
}
  1. Run query file generation for a query assigning an optional
insert Example {
  name := <optional str>$name
}
  1. This generates a seemingly valid query file that fails at runtime with an optional arg
// GENERATED by @edgedb/generate v0.4.1

import type {Executor} from "edgedb";

export type TestArgs = {
  "name"?: string | null;
};

export type TestReturns = {
  "id": string;
};

export async function Test(client: Executor, args: TestArgs): Promise<TestReturns> {
  return client.queryRequiredSingle(`\
insert Example {
  name := <optional str>$name
}`, args);

}

jackfischer avatar Feb 10 '24 21:02 jackfischer

It occurs to me that this might be query-file specific: in normal edgeql, the runtime failure is all you need, and in QB, this can be enforced. This makes me think it might be more disruptive than I thought to add this mechanism & more of an FR

jackfischer avatar Feb 11 '24 13:02 jackfischer

Yeah, and having flexibility in the arguments means you can do things like `?? "default value" or use optional arguments for updates.

Maybe the kind of static analysis you're looking for is whether we can know statically if we're not providing the right type of value to an expression like name := arg? Or maybe as part of the query generation you'd want to perhaps attempt the query with some kind of arbitrary data of the parameter type and see if it throws a runtime error and fail to codegen the query?

scotttrinh avatar Feb 12 '24 14:02 scotttrinh

Certainly agree on the argument being optional for purposes like like `?? "default value" or updates.

Maybe the kind of static analysis you're looking for is whether we can know statically if we're not providing the right type of value to an expression like name := arg?

Bingo.

Or maybe as part of the query generation you'd want to perhaps attempt the query with some kind of arbitrary data of the parameter type and see if it throws a runtime error and fail to codegen the query?

This is an interesting implementation idea and has the added benefit of statically surfacing any edgedb bugs that come along. However, it seems difficult for data dependent situations like conditionals or unless conflict. However, you'd know about the feasibility of that much better than I would.

jackfischer avatar Feb 12 '24 14:02 jackfischer

Yeah, statically analyzing the query to ensure the query types are correct at introspection time seems like a doable thing! I'll move this to the edgedb-js repo and talk it over with the compiler team to see how feasible it is.

scotttrinh avatar Feb 12 '24 15:02 scotttrinh

We do do static checking of types and cardinalities. The issue here is that for inserts and updates, we intentionally don't enforce whether it is required statically, because required links can very rarely be determined statically to exist. (Since they usually come from a select+filter, which we can't know will find anything.)

msullivan avatar Feb 12 '24 16:02 msullivan

I see (similar to the fundamental inability to know cardinality statically in 6694?) This situation makes sense for links, though one can enforce that say, a required UUID argument for a filter is populated? As you say that doesn't offer guaranteed protection at runtime but at least ensures the query is written correctly?

jackfischer avatar Feb 12 '24 18:02 jackfischer