diff --git a/.github/brand/logo-dark.svg b/.github/brand/logo-dark.svg new file mode 100644 index 0000000..6ba2693 --- /dev/null +++ b/.github/brand/logo-dark.svg @@ -0,0 +1 @@ +restloom logo \ No newline at end of file diff --git a/.github/brand/logo-light.svg b/.github/brand/logo-light.svg new file mode 100644 index 0000000..6c3252a --- /dev/null +++ b/.github/brand/logo-light.svg @@ -0,0 +1 @@ +restloom logo \ No newline at end of file diff --git a/.github/brand/social-preview.png b/.github/brand/social-preview.png new file mode 100644 index 0000000..3b5f8cd Binary files /dev/null and b/.github/brand/social-preview.png differ diff --git a/README.md b/README.md index fec6421..16ca206 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,9 @@ -# restloom +

+ + + restloom + +

A REST API generated from your database's catalog. Name the schemas or tables to serve, and restloom reads their columns, types, keys and relations, and answers queries like this one: diff --git a/conformance/dialects-doc.test.mjs b/conformance/dialects-doc.test.mjs new file mode 100644 index 0000000..8c449e5 --- /dev/null +++ b/conformance/dialects-doc.test.mjs @@ -0,0 +1,36 @@ +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { postgres } from '../packages/postgres/dist/index.js'; +import { mysql } from '../packages/mysql/dist/index.js'; +import { mssql } from '../packages/mssql/dist/index.js'; +import { sqlite } from '../packages/sqlite/dist/index.js'; + +// The table in docs/dialects.md is what readers compare databases by, on the +// site too. It must say what each dialect's capabilities say. +const DIALECTS = { + '@crudy/restloom-postgres': postgres({}), + '@crudy/restloom-mysql': mysql({}), + '@crudy/restloom-mssql': mssql({}), + '@crudy/restloom-sqlite': sqlite({ pragma() {} }), +}; + +const rows = readFileSync(new URL('../docs/dialects.md', import.meta.url), 'utf8') + .split('\n') + .filter((line) => line.startsWith('| `@crudy/restloom-')) + .map((line) => line.split('|').slice(1, -1).map((cell) => cell.trim())); + +test('docs/dialects.md lists every dialect', () => { + assert.deepEqual(rows.map((r) => r[0].replaceAll('`', '')).sort(), Object.keys(DIALECTS).sort()); +}); + +for (const [pkg, dialect] of Object.entries(DIALECTS)) { + test(`docs/dialects.md says what ${pkg} can do`, () => { + const [, , , written, estimated, rowSecurity, procedures] = rows.find((r) => r[0] === `\`${pkg}\``); + const c = dialect.capabilities; + assert.equal(/RETURNING|OUTPUT/.test(written), c.returning, 'written keys'); + assert.equal(estimated !== 'no', c.estimatedCount, 'estimated count'); + assert.equal(rowSecurity !== 'no', c.rowSecurity, 'row security'); + assert.equal(procedures !== 'none', c.procedures, 'procedures'); + }); +}