sqlx-ts icon indicating copy to clipboard operation
sqlx-ts copied to clipboard

Programmatic JS API

Open JulianCataldo opened this issue 1 year ago • 2 comments

Hello!

Calling sqlx-ts from a Node script could be very handy, so we can integrate it in broader codegen workflow. It could just take an input string and output a string, so we (users) could handle watching and writing files ourselves.

I'm not sure if it's feasible due to the JS/Rust bindings stuff, etc.

What do you think?

Thank you

JulianCataldo avatar Jun 17 '24 17:06 JulianCataldo

Hello, this is interesting. Could you explain a bit more about the codegen use case (and being able to call native sqlx-ts from Node?)? I've been using sqlx-ts CLI primarily for local DX and CI/CD integration.

If watching for file changes is needed, I recommend calling sqlx-ts binary using nodemon (or anything that you prefer).

JasonShin avatar Jun 18 '24 04:06 JasonShin

Hey!

This is the script I'm using right now, the goal is to have a live feedback loop during dev.

import { exec as _exec } from 'node:child_process';
import { mkdir, readFile, writeFile } from 'node:fs/promises';
import { dirname, join, normalize } from 'node:path';
import { promisify } from 'node:util';

import { watch } from 'chokidar';

const exec = promisify(_exec);

const TMP = './.tmp';

await mkdir(TMP).catch(() => null);

watch(['./src/database/*/**/*.ts', '!**/*.queries.ts']).on(
  'all',
  async (event, file) => {
    const dest = join(TMP, file);
    await mkdir(dirname(dest), { recursive: true });
    const fileContent = await readFile(file, 'utf8');

    // NOTE: We need to remove template expression (`${foo}`).
    // They're not supported by `sqlx-ts`
    const fileWithoutTemplateExpressions = fileContent.replaceAll(
      /\${(.*?)}/g,
      '?',
    );

    await writeFile(dest, fileWithoutTemplateExpressions);

    const resultSqlTs = await exec(
      `pnpm sqlx-ts '${TMP}' --config .sqlxrc.json`,
    );
    console.log(resultSqlTs);
    const resultPrettier = await exec(`pnpm prettier --write ${TMP}/**/*.ts`);
    console.log(resultPrettier);

    const sourceQueries = dest.replace(/\.ts$/, '.queries.ts');
    const destQueries = sourceQueries.replace(normalize(TMP), '.');
    console.log({ sourceQueries, destQueries });

    const queriesContent = await readFile(sourceQueries, 'utf8');
    await writeFile(
      destQueries,
      `/* /!\\ AUTO-GENERATED /!\\ */\n\n${queriesContent}`,
    );
  },
);

(Unrelated but the Prettier part can be handled with a JS API, too, I was just too lazy to set it up, and it's just the finishing touch).

I'm doing several stuff here, and if I want to alter the input/output, I have to use the filesystem as a medium, which is sub-optimal.

With a JS API, I could just call something like (skipping the bike-shedding):

import { generateTypesForFile } from 'sqlx-ts';

// ...

const { result, errors } = await generateTypesForFile({ input: '...a string from the TS/whatever file…' });

// Do something with the string result
// ...

I hope this use case is more clear for you :)

Thank you

JulianCataldo avatar Jun 18 '24 18:06 JulianCataldo