Remix.run Logo
simonw 5 hours ago

A handy trick for column types is check constraints.

You can define constraints on a column that ensure it is text that's valid JSON for example:

  CREATE TABLE documents (
    id INTEGER PRIMARY KEY,
    data TEXT NOT NULL
      CHECK (
        json_valid(data)
        json_type(data) = 'object'
      )
  );
Or to ensure specific keys:

  CREATE TABLE documents (
    id INTEGER PRIMARY KEY,
    data TEXT NOT NULL CHECK (
      json_valid(data)
      AND json_type(data) = 'object'
      AND json_type(data, '$.name') = 'text'
      AND json_type(data, '$.age') = 'integer'
    )
  );
You can even use this for things like enforcing a valid YYYY-MM-DD date, though that gets a bit convoluted:

  CREATE TABLE events (
    id INTEGER PRIMARY KEY,
    occurred_on TEXT NOT NULL CHECK (
      length(occurred_on) = 10
      AND occurred_on GLOB
        '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
      AND date(occurred_on, '+0 days') = occurred_on
    )
  );
simonw 16 minutes ago | parent [-]

Correction to the above: it should use

  json_type(data, '$.name') IS 'text'
Using = fails because a missing key returns null and in SQLite null = 'text' is null: https://latest.datasette.io/_memory/-/query?sql=select+null%...