{"html_url": "https://github.com/simonw/sqlite-utils/issues/358#issuecomment-1257136801", "issue_url": "https://api.github.com/repos/simonw/sqlite-utils/issues/358", "id": 1257136801, "node_id": "IC_kwDOCGYnMM5K7mKh", "user": {"value": 11597658, "label": "luxint"}, "created_at": "2022-09-25T07:15:07Z", "updated_at": "2022-09-25T07:15:59Z", "author_association": "NONE", "body": "HI Simon, \r\n\r\nlooks good, I noticed you wanted to use a regex to detect it, you might be interested in [github.com/iafisher/sqliteparser](https://github.com/iafisher/sqliteparser) which creates an ast of the create table statement, not every option supported yet but i forked it and am adding all the possible options in a create table (and create index) statement. ", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1082651698, "label": "Support for CHECK constraints"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/sqlite-utils/issues/358#issuecomment-1255341690", "issue_url": "https://api.github.com/repos/simonw/sqlite-utils/issues/358", "id": 1255341690, "node_id": "IC_kwDOCGYnMM5K0v56", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-09-22T17:35:23Z", "updated_at": "2022-09-22T17:35:23Z", "author_association": "OWNER", "body": "Make me think also that `sqlite-utils create-table` should have an option to dump out the SQL without actually creating the table.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1082651698, "label": "Support for CHECK constraints"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/sqlite-utils/issues/358#issuecomment-1255340974", "issue_url": "https://api.github.com/repos/simonw/sqlite-utils/issues/358", "id": 1255340974, "node_id": "IC_kwDOCGYnMM5K0vuu", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-09-22T17:34:45Z", "updated_at": "2022-09-22T17:34:45Z", "author_association": "OWNER", "body": "A few other recipes off the top of my head:\r\n\r\n- `title:maxlength:20` - set a max length, `length(title) <= 20`\r\n- `created:date` - check for `yyyy-mm-dd` date, `select :date == date(:date) is not null` ([demo](https://latest.datasette.io/_memory?sql=select+%3Adate+%3D%3D+date%28%3Adate%29+is+not+null&date=2022-01-01))\r\n- `age:positiveint` - check `age` is a positive integer, `printf('%', age) = age and age > 0` (untested)", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1082651698, "label": "Support for CHECK constraints"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/sqlite-utils/issues/358#issuecomment-1255333969", "issue_url": "https://api.github.com/repos/simonw/sqlite-utils/issues/358", "id": 1255333969, "node_id": "IC_kwDOCGYnMM5K0uBR", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-09-22T17:29:09Z", "updated_at": "2022-09-22T17:29:09Z", "author_association": "OWNER", "body": "Quick demo of a check constraint for JSON validation:\r\n```\r\nsqlite> create table test (id integer primary key, tags text, check (json(tags) is not null));\r\nsqlite> sqlite> insert into test (tags ('[\"one\", \"two\"]');\r\nsqlite> insert into test (tags) values ('[\"one\", \"two\"');\r\nError: stepping, malformed JSON (1)\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1082651698, "label": "Support for CHECK constraints"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/sqlite-utils/issues/358#issuecomment-1255332217", "issue_url": "https://api.github.com/repos/simonw/sqlite-utils/issues/358", "id": 1255332217, "node_id": "IC_kwDOCGYnMM5K0tl5", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-09-22T17:27:34Z", "updated_at": "2022-09-22T17:27:34Z", "author_association": "OWNER", "body": "I've been thinking about this more recently.\r\n\r\nI think the first place to explore these will be in the `create-table` command (and underlying APIs).\r\n\r\nRelevant docs: https://www.sqlite.org/lang_createtable.html#check_constraints\r\n\r\n> A CHECK constraint may be attached to a column definition or specified as a table constraint. In practice it makes no difference. Each time a new row is inserted into the table or an existing row is updated, the expression associated with each CHECK constraint is evaluated and cast to a NUMERIC value in the same way as a [CAST expression](https://www.sqlite.org/lang_expr.html#castexpr). If the result is zero (integer value 0 or real value 0.0), then a constraint violation has occurred. If the CHECK expression evaluates to NULL, or any other non-zero value, it is not a constraint violation. The expression of a CHECK constraint may not contain a subquery.\r\n\r\nSomething like this:\r\n\r\n sqlite-utils create-table data.db entries id integer title text tags text --pk id --check tags:json\r\n\r\nWhere `--check tags:json` uses a pre-baked recipe for using the SQLite JSON function to check that the content is valid JSON and reject it otherwise.\r\n\r\nThen can bundle a bunch of other pre-baked recipes, but also support the following:\r\n\r\n --check 'x > 3' --check 'length(phone) >= 10'\r\n\r\nThe besign reason for the `column:recipe` format here is to reuse `--check` for both pre-defined recipes that affect a single column AND for freeform expressions that get added to the end of the table.\r\n\r\nDetecting `column name:recipe` with a regex feels safe to me.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1082651698, "label": "Support for CHECK constraints"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/sqlite-utils/issues/358#issuecomment-996482595", "issue_url": "https://api.github.com/repos/simonw/sqlite-utils/issues/358", "id": 996482595, "node_id": "IC_kwDOCGYnMM47ZR4j", "user": {"value": 11597658, "label": "luxint"}, "created_at": "2021-12-17T06:57:51Z", "updated_at": "2021-12-17T23:24:16Z", "author_association": "NONE", "body": "> This goes beyond the `transform()` method - the curious methods that create new SQL tables could benefit from the ability to add `CHECK` constraints too.\r\n> \r\n> I haven't used these myself, do you have any `CREATE TABLE` examples that use them that you can share?\r\n\r\nI'm using them myself for the first time as well, this is a tutorial of how to use (and change) them in sqlite: https://www.sqlitetutorial.net/sqlite-check-constraint/", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1082651698, "label": "Support for CHECK constraints"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/sqlite-utils/issues/358#issuecomment-996232461", "issue_url": "https://api.github.com/repos/simonw/sqlite-utils/issues/358", "id": 996232461, "node_id": "IC_kwDOCGYnMM47YU0N", "user": {"value": 9599, "label": "simonw"}, "created_at": "2021-12-16T22:10:39Z", "updated_at": "2021-12-16T22:10:39Z", "author_association": "OWNER", "body": "This goes beyond the `transform()` method - the curious methods that create new SQL tables could benefit from the ability to add `CHECK` constraints too.\r\n\r\nI haven't used these myself, do you have any `CREATE TABLE` examples that use them that you can share?", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1082651698, "label": "Support for CHECK constraints"}, "performed_via_github_app": null}