kysely-org / kysely

A type-safe typescript SQL query builder
https://kysely.dev
MIT License
10.72k stars 271 forks source link

How to do `using gin (<column2> gin_trgm_ops, <column2>, <column3>);` with Kysely? #1190

Open lancejpollard opened 2 weeks ago

lancejpollard commented 2 weeks ago

How can you write this sort of query with Kysely?

CREATE INDEX idx_words_lang_phon ON searches 
USING gin (text gin_trgm_ops, language_id, is_phonetic);

I know you can do this so far:

await db.schema
  .createIndex('searches_text_index')
  .on('searches')
  .using('gin')
  .column('text')
  .execute()

But how about specifying the gin_trgm_ops and the rest of the columns, is there a nice way? Perhaps:

await db.schema
  .createIndex('searches_text_with_other_columns_index')
  .on('searches')
  .using('gin')
  .columns(['text gin_trgm_ops', 'language_id', 'is_phonetic'])
  .execute()

ClaudeAI is suggesting these two:

await db.schema
  .raw(`
    CREATE INDEX idx_words_lang_phon ON searches 
    USING gin (text gin_trgm_ops, language_id, is_phonetic)
  `);

await db.schema.createIndex('idx_words_lang_phon')
  .on('searches')
  .expression(sql`(text gin_trgm_ops, language_id, is_phonetic) USING gin`)
  .execute()

Any of these work or ideal? What is recommended?

And same for this:

CREATE INDEX idx_words_prefix_fuzzy ON searches 
USING gin (text gin_trgm_ops)
WHERE length(text) >= 3;

Is that just this? (Is there a better way)?

await db.schema
  .createIndex('idx_words_prefix_fuzzy')
  .on('searches')
  .using('gin')
  .column('text')
  .where('length(text)', '>=', 3)
  .execute()

Also (tangent), do I need to do this somewhere (and how to do it in Kysely)?

CREATE EXTENSION IF NOT EXISTS pg_trgm;

Thanks for the help.

lancejpollard commented 2 weeks ago
await createGinIndex(
  db,
  'searches_text_language_gin_index',
  'searches',
  ['language_id', 'text gin_trgm_ops'],
  'WHERE is_phonetic = FALSE',
)

async function createGinIndex(
  db: Kysely<any>,
  indexName: string,
  tableName: string,
  columns: Array<string>,
  extra: string
) {
  const columnsStr = columns.join(", ");
  const query = sql`CREATE INDEX ${indexName} ON ${tableName} USING gin (${columnsStr}) ${extra}`;
  console.log(query);
  await query.execute(db);
  // let builder = db.schema
  //   .createIndex(indexName)
  //   .on(tableName)
  //   .using('gin')
  //   .expression(sql`USING gin (${columnsStr})`)
  // if (cb) {
  //   builder = cb(builder)
  // }
  // return await builder.execute()
}

Error:

RawBuilderImpl {}
failed to execute migration "foo_0001"
failed to migrate
error: syntax error at or near "$1"