Skip to content

API

All of the options that are mentioned below should be configured in your eslintrc config file under the rule "@ts-safeql/check-sql". Be sure to read the Configuration guide first.

useConfigFile

If set to true, SafeQL will look for a safeql.config.ts file in the root of your project.

json
{
  "useConfigFile": true
}
ts
// safeql.config.ts
import { defineConfig } from "@ts-safeql/eslint-plugin";

export default defineConfig({
  connections: {
    // ...
  },
});

INFO

This option cannot be used with connections.

connections

Can be either an object that represents a single connection, or an array that represents multiple connections.

In most use cases, when you have only one database connection, you can pass a single object that represents the type of the connection. For example:

json
{
  "connections": {
    "databaseUrl": "postgres://user:pass@localhost:5432/dbname",
    "targets": [{ "tag": "sql" }]
  }
}

When working with multiple connections, you can pass an array of connections:

json
{
  "connections": [
    {
      "databaseUrl": "postgres://user:pass@localhost:5432/dbname",
      "targets": [{ "tag": "sql" }]
    },
    {
      "databaseUrl": "postgres://user:pass@localhost:5432/dbname2",
      "targets": [{ "tag": "prisma.+($queryRaw|$executeRaw)" }]
    }
  ]
}

connections.databaseUrl

The database URL that the plugin will use to infer the types of the queries, and report any errors.

INFO

connections.migrationsDir

The path to the directory where your database migrations are located (only .sql migration files supported currently). For example:

json
{
  "connections": {
    "migrationsDir": "prisma/migrations"
    // ...
  }
}

INFO

connections.watchMode (Optional)

Whether or not to recreate the shadow database when a migration file is changed. This option is only relevant when migrationsDir is used.

If no value is provided, then it will default to true.

json
{
  "connections": {
    "migrationsDir": "...",
    "watchMode": true
    // ...
  }
}

INFO

connections.connectionUrl (Optional)

If no value is provided, it will fallback to:

postgres://postgres:postgres@localhost:5432/postgres

When using migrations, we don't have a database URL. In order to connect to Postgres, we need to connect to an existing database. The default value is:

A connection URL is required to create a shadow database (and drop it after) to query the database metadata so it can infer the types of the queries, and report any errors.

SHADOW DATABASE

Shadow database is a database that is being used to query the migrations folder metadata. It is created and dropped automatically by SafeQL.

INFO

connections.databaseName (Optional)

The name of the shadow database that will be created and dropped automatically by SafeQL. If no value is provided, the default value is safeql_${underscore_dir_name}_{dir_path_hash}. Read more in connectionUrl option. For example:

json
{
  "connections": {
    "migrationsDir": "...",
    "databaseName": "my_shadow_db"
    // ...
  }
}

INFO

connections.targets.tag

The targets tell SafeQL where to look for the queries. It's an array of tag and wrapper targets.

json
{
  "connections": {
    // ...
    "targets": [
      { "tag": "sql1" }
      { "tag": "sql2" }
      { "wrapper": "conn.query" }
      { "wrapper": "conn.+(query|execute)" }
      { "wrapper": { "regex": "conn2.+(query|execute)" } }
      ]
  }
}

connections.targets.tag

The name of the tag (which could be a string, regex, or a glob pattern using minimatch) that SafeQL will use to analyze the queries. For example:

json
{
  "connections": {
    // ...
    "targets": [{ "tag": "sql" }]
    // or use a glob pattern:
    // "targets": [{ "tag": "prisma.+($queryRaw|$executeRaw)" }]
    // or use regex:
    // "targets": [{ "tag": "prisma\.($queryRaw|$executeRaw)" }]
  }
}

for:

ts
const sql = postgres();

sql`SELECT id FROM users`;

// will be fixed to
sql<{ id: number }>`SELECT id FROM users`;

TIP

If you're using Postgres.js, then be sure to check out the guide on how to use SafeQL with Postgres.js.

INFO

  • this option cannot be used with wrapper as a sibling property.

connections.targets.wrapper

The wrapper function that receives the sql tag as an argument:

json
{
  "connections": {
    // ...
    "targets": [{ "wrapper": "conn.query" }]
  }
}
ts
const conn = new Client();

conn.query(...);

INFO

  • this option cannot be used with tag as a sibling property.

connections.targets.maxDepth (Optional)

By default, SafeQL assumes that each wrapper has a direct descendant of an sql tag. In some cases, you may want to increase the depth of the sql tag lookup. For example:

ts
conn.query(sql`SELECT id FROM users`); // depth = 0
conn.query([sql`SELECT id FROM users`]); // depth = 1
conn.query(...sql`SELECT id FROM users`); // depth = 1
conn.query(...[sql`SELECT id FROM users`]); // depth = 2

In this case, you can use the maxDepth option to specify the maximum depth of the sql tag. For example:

json
{
  "connections": {
    // ...
    "targets": [
      {
        "wrapper": "conn.query",
        "maxDepth": 2
      }
    ]
  }
}

connections.targets.transform (Optional)

Transform the end result of the query. For example, if you want to transform the result of the query to be an array of objects, you can use the following:

json
{
  "connections": {
    // ...
    "targets": [
      {
        // ...
        "transform": "{type}[]"
      }
    ]
  }
}

EXAMPLES

  • "{type}[]" will transform the type to an array of the type.
  • ["colname", "x_colname"] will replace colname with x_colname in the type.
  • ["{type}[]", ["colname", x_colname"]] will do both

connections.targets.fieldTransform (Optional)

Transform the (column) field key. Can be one of the following:

  • "snake" - userIduser_id
  • "camel" - user_iduserId
  • "pascal" - user_idUserId
  • "screaming snake" - user_idUSER_ID
json
{
  "connections": {
    // ...
    "targets": [
      {
        // ...
        "fieldTransform": "camel"
      }
    ]
  }
}

connections.targets.skipTypeAnnotations (Optional)

Skip adding type annotations to the query. This is useful if you're using a library that doesn't support type annotations. Usage:

json
{
  "connections": {
    // ...
    "targets": [
      {
        // ...
        "skipTypeAnnotations": true
      }
    ]
  }
}

connections.keepAlive (Optional)

True by default. If set to false, the connection will be closed after the query is executed. This is not recommended, and should only be used if you're sure that the connection should be closed.

connections.overrides.types (Optional)

INFO

Please note that SafeQL won't actually parse the type, since SafeQL runs only in the tooling system (i.e, not in runtime).

Override the default type mapping. For example, if you want to use LocalDate instead of Date for the date type, you can use the following:

json
{
  "connections": {
    "overrides": {
      "types": {
        "date": "LocalDate"
      }
    }
  }
}

Sometimes, the TypeScript type of the parameter (sql variable) is not the same as the type of the result. For example:

ts
import postgres from "postgres";
import { sql } from "./sql";

function run(value: postgres.Parameter<LocalDate>) {
  const result = sql<{ date: LocalDate }>`SELECT ${value}`;
  // ...
}

In this case, you can use the following syntax:

json
{
  "connections": {
    "overrides": {
      "types": {
        "date": {
          // the type of the parameter (can be a regex or a glob pattern)
          "parameter": "Parameter<LocalDate>",
          // the generated type
          "return": "LocalDate"
        }
      }
    }
  }
}

connections.overrides.columns (Optional)

INFO

While SafeQL generally succeeds in inferring column types, it sometimes cannot, particularly with JSONB columns where the type is not explicitly defined. Additionally, there may be scenarios where you want to enforce a specific type for a column.

json
{
  "connections": {
    "overrides": {
      "columns": {
        "table_name.column_name": "CustomType"
      }
    }
  }
}