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

Query builder builds broken query

Open elprans opened this issue 2 years ago • 2 comments

Code The code causing the error.

async function run() {
  const query1 = e.select(
    e.select(e.Movie, (movie) => ({
      filter: e.op(movie.title, '=', 'Dune')
    })),
    (movie) => ({
      comp: movie.is(e.Movie)
    }),
  );

  console.log(query1.toEdgeQL());
  const result = await query1.run(client);
}

Schema

From edgedb/edgedb-movies

Generated EdgeQL

WITH
  __withVar_2 := (__scope_1_defaultMovie.title = "Dune"),
  __scope_0_defaultMovie := (
    WITH
      __scope_1_defaultMovie := DETACHED default::Movie
    SELECT __scope_1_defaultMovie {
      id
    }
    FILTER __withVar_2
  )
SELECT __scope_0_defaultMovie {
  single comp := (__scope_0_defaultMovie {id})[IS default::Movie]
}

Error or desired behavior

InvalidReferenceError: object type or alias 'default::__scope_1_defaultMovie' does not exist
   |
 2 |   __withVar_2 := (__scope_1_defaultMovie.title = "Dune"),
   |                   ^^^^^^^^^^^^^^^^^^^^^^

Versions (please complete the following information):

  • edgedb-js version (e.g. 1.4.1;):
  • @edgedb/generate version (e.g. 0.4.1;):

elprans avatar Dec 14 '23 03:12 elprans

Related #615

scotttrinh avatar Dec 14 '23 13:12 scotttrinh

@scotttrinh this issue is not about is operator. Here's example of query without is:

  const user = e.select(e.User, () => ({
    filter_single: { id: userId }
  }))

  const words = e.select(user.words, word => ({
    filter: e.op(word.language, '=', user.language),
  }))

  const query = e.with([user, words], e.select(words, word => ({
    trivial: e.op(word, 'in', user.words),
  })))

it is being converted to such EdgeQL query:

WITH
  __withVar_2 := (
    WITH
      __scope_1_defaultUser := DETACHED default::User
    SELECT __scope_1_defaultUser {
      id
    }
    FILTER (__scope_1_defaultUser.id = <std::uuid>"...")
  ),
  __withVar_5 := (__scope_3_defaultVocabularyWord.language = __withVar_2.language),
  __withVar_4 := (
    WITH
      __scope_3_defaultVocabularyWord := __withVar_2.words
    SELECT __scope_3_defaultVocabularyWord {
      id
    }
    FILTER __withVar_5
  ),
  __scope_0_defaultVocabularyWord := __withVar_4
SELECT __scope_0_defaultVocabularyWord {
  single trivial := ((__scope_0_defaultVocabularyWord {id}) in __withVar_2.words)
}

The problem is that variable __withVar_5 being introduced. It only used inside the __withVar_4 block and it refers to the variable __scope_3_defaultVocabularyWord which is declared (and hence accessible only) inside __withVar_4 block.

awerlogus avatar Jan 25 '24 23:01 awerlogus