Files
supabase/packages/ui-patterns/SqlToRest/faqs.ts
T
Greg RichardsonandCharis 3f1df65bba SQL to REST translator (#25978)
* feat: sql-to-rest poc

* feat: sql-to-supabase-js poc

* chore: upgrade to libpg-query@15

* feat: sql-to-rest docs tool

* docs(sql-to-rest): add introduction

* docs: wording improvements

* fix: theme

* chore: tailwind placeholder

* feat(sql-to-rest): limit, offset, and range

* feat(sql-to-rest): sort by

* fix(sql-to-rest): ui theme

* feat(sql-to-rest): casts

* feat(sql-to-rest): dynamic faqs in ui

* feat(sql-to-rest): improve ui responsiveness

* feat(sql-to-rest): more advanced faqs in ui

* feat(sql-to-rest): http and curl syntax highlighting

* feat(sql-to-rest): baseUrl in http/curl rendering

* docs(sql-to-rest): clarification on curl flags

* feat(sql-to-rest): more faqs

* refactor(sql-to-rest): split faqs into own file

* refactor(sql-to-rest): move formatters to sql-to-rest package

* docs(sql-to-rest): move page to new tools section

* feat(sql-to-rest): joins and resource embeddings

* chore(sql-to-rest): rename 'convert' to 'translate'

* feat(sql-to-rest): add faqs

* feat(sql-to-rest): ui improvements

* feat(sql-to-rest): faq title adjustment

* feat(sql-to-rest): link to client lib docs

* feat(sql-to-rest): assumptions

* feat(sql-to-rest): friendly 'not supported yet' errors

* feat(sql-to-rest): json columns

* feat(sql-to-rest): remove curl -G flag if unused

* feat(sql-to-rest): better error handling

* chore: revert accidental rls ai work

* fix: build errors

* fix(sql-to-rest): theme

* feat(sql-to-rest): change base url

* feat(sql-to-rest): basic aggregate poc

* feat(sql-to-rest): group by

* feat(sql-to-rest): more group by checks

* feat(sql-to-rest): count(*) special case

* fix(sql-to-rest): tests

* feat(sql-to-rest): faq on 'and' operator

* fix(sql-to-rest): error messages

* fix(sql-to-rest): multiple filters on same column

* refactor(sql-to-rest): error hints

* feat(sql-to-rest): match and imatch

* feat(sql-to-rest): in operator

* feat(sql-to-rest): parsing error hints

* feat(sql-to-rest): default language to curl

* feat(sql-to-rest): format on cmd+s

* feat(sql-to-rest): format initial value

* fix(sql-to-rest): turn off tab query group

* feat(sql-to-rest): improve wording in error messages

* feat(sql-to-rest): animated code blocks

* feat(sql-to-rest): more error hints

* fix(sql-to-rest): strip primary relation prefix from columns

* feat(sql-to-rest): json column in order by clause

* feat(sql-to-rest): validate all referenced relations exist in from clause

* refactor(sql-to-rest): split core sql-to-rest lib into separate repo

* feat(sql-to-rest): upgrade to v0.1.1

* feat(sql-to-rest): upgrade to v0.1.2

* feat(sql-to-rest): upgrade to v0.1.4

* chore: upgrade libpg-query

* feat: update 'create a pr' link

* fix: app builds

* fix: prettier

* fix: typecheck

* fix: studio tests

* chore: remove console.log

Co-authored-by: Charis <26616127+charislam@users.noreply.github.com>

* docs(sql-to-rest): remove broken link to client libraries

---------

Co-authored-by: Charis <26616127+charislam@users.noreply.github.com>
2024-05-22 12:37:01 -06:00

228 lines
7.7 KiB
TypeScript

import { stripIndent } from 'common-tags'
import { someFilter } from '@supabase/sql-to-rest'
import { ResultBundle } from './util'
export type Faq = {
id: string
condition: (result: ResultBundle) => boolean
question: string
answer: string
}
export const faqs: Faq[] = [
{
id: 'what-is-curl',
condition: (result) => result.language === 'curl',
question: 'What is `curl`?',
answer: stripIndent`
\`curl\` is a popular command-line tool for performing HTTP requests. It's useful for testing your API to make sure it returns what you expect.
You can also import \`curl\` commands into tools like [Postman](https://learning.postman.com/docs/getting-started/importing-and-exporting/importing-curl-commands/) via copy-paste.
`,
},
{
id: 'what-is-http',
condition: (result) => result.language === 'http',
question: 'What format is this?',
answer: stripIndent`
This shows the raw HTTP request sent to PostgREST. It gives you a detailed view of the exact HTTP method, path, headers, and body sent to the API.
`,
},
{
id: 'what-is-supabase-js',
condition: (result) => result.language === 'js',
question: 'What library is this?',
answer: stripIndent`
This snippet uses [\`supabase-js\`](https://github.com/supabase/supabase-js), a JavaScript/TypeScript client that provides a convenient SDK wrapper around your project's API.
See [Installing](/docs/reference/javascript/installing) to get started.
`,
},
{
id: 'curl-flags',
condition: (result) =>
result.language === 'curl' && result.method === 'GET' && result.params.size > 0,
question: 'What do `-G` and `-d` do?',
answer: stripIndent`
In \`curl\`, \`-d\` is short for \`--data-urlencode\` and is typically used to add payload to \`POST\` requests.
The \`-G\` flag tells \`curl\` to apply the \`-d\` data as \`GET\` request query parameters instead, which is a bit more readable than adding them directly to the path.
`,
},
{
id: 'how-do-aliases-work',
condition: ({ statement }) =>
// Show this if there is at least one alias
statement.targets.some((target) => target.alias),
question: 'How do aliases work?',
answer: stripIndent`
PostgREST supports [renaming columns](https://postgrest.org/en/latest/references/api/tables_views.html#renaming-columns) by prefixing the column name with an alias and a colon:
*Request*
\`\`\`bash
/books?select=myTitle:title
\`\`\`
*Response*
\`\`\`json
[
{
"myTitle": "The Cheese Tax"
}
]
\`\`\`
`,
},
{
id: 'why-alias-lower-case',
condition: ({ statement }) =>
// Show this if there is at least one alias and no aliases have capital letters
statement.targets.some((target) => target.alias) &&
!statement.targets.some(
(target) => target.alias && target.alias !== target.alias.toLowerCase()
),
question: 'Why is my alias lower case?',
answer: stripIndent`
Postgres converts all SQL identifiers to lowercase by default. To keep casing when converting from SQL, wrap your alias in double quotes:
\`\`\`sql
select
title as "myTitle"
from
books
\`\`\`
`,
},
{
id: 'how-does-and-work',
condition: ({ statement }) =>
// Show this if there is at least one `AND` operator
!!statement.filter &&
statement.filter.type === 'logical' &&
statement.filter.operator === 'and',
question: 'How does the `AND` operator work?',
answer: stripIndent`
PostgREST treats each \`AND\` expression as a separate query parameter.
For example the following SQL:
\`\`\`sql
select
*
from
books
where
description ilike '%cheese%' and
pages > 100
\`\`\`
is equivalent to this API request:
\`\`\`bash
/books?description=ilike.*cheese*&pages=gt.100
\`\`\`
There are exceptions when you have nested \`AND\` expressions, but otherwise this provides an API most consistent with other REST APIs.
`,
},
{
id: 'how-do-joins-work',
condition: ({ statement }) =>
// Show this if there is at least one resource embedding
statement.targets.some((target) => target.type === 'embedded-target'),
question: 'How do joins work?',
answer: stripIndent`
PostgREST supports joins through [resource embeddings](https://postgrest.org/en/latest/references/api/resource_embedding.html). Resource embeddings are defined within the \`select\` field using the syntax:
\`\`\`bash
/books?select=authors(name)
\`\`\`
The above query will join \`books\` with \`authors\` and select the name of the author who wrote the book. The fields inside the parenthesis refer to those in the joined table.
Some important notes about resource embeddings:
- A [foreign key](https://postgrest.org/en/latest/references/api/resource_embedding.html#foreign-key-joins) _must_ exist between the tables, otherwise PostgREST won't know how to join them
- Because of this, not all joins are supported - only those that join on the foreign key columns
- Joins are \`LEFT\` by default. To perform an \`INNER\` join, add \`!inner\` to the embedded resource:
\`\`\`bash
/books?select=author!inner(name)
\`\`\`
PostgREST only supports \`LEFT\` and \`INNER\` joins.
- Resource embeddings are nested by default:
*Request*
\`\`\`bash
/books?select=title,author(name)
\`\`\`
*Response*
\`\`\`json
{
"title": "The Cheese Tax",
"author": {
"name": "Bobby Bobson"
}
}
\`\`\`
To flatten the resource embedding into its parent, use the [spread syntax](https://postgrest.org/en/latest/references/api/resource_embedding.html#spread-embedded-resource):
*Request*
\`\`\`bash
/books?select=...author(authorName:name)
\`\`\`
*Response*
\`\`\`json
{
"authorName": "Bobby Bobson"
}
\`\`\`
Note that we also aliased the author's name as \`authorName\` for better clarity (otherwise it would have been just \`name\`).
Only many-to-one and one-to-one relationships support the spread syntax.
`,
},
{
id: 'why-percent-sign-conversion',
condition: ({ type, statement }) =>
// Show this if this is an HTTP render, there is a like/ilike filter, and at least one filter contains '%' character
type === 'http' &&
!!statement.filter &&
someFilter(
statement.filter,
(filter) =>
['like', 'ilike'].includes(filter.operator) &&
typeof filter.value === 'string' &&
filter.value.includes('%')
),
question: 'Why is `%` getting converted to `*`?',
answer: stripIndent`
PostgREST [supports](https://postgrest.org/en/latest/references/api/tables_views.html#operators) \`*\` as an alias for \`%\` in \`LIKE\` and \`ILIKE\` expressions to avoid URL encoding.
`,
},
{
id: 'why-range-supabase-js',
condition: (result) =>
// Show this if viewing the JS code and there is both a limit and offset
result.language === 'js' &&
result.statement.limit?.count !== undefined &&
result.statement.limit.offset !== undefined,
question: 'Why `range()` instead of `limit()` and `offset()`?',
answer: stripIndent`
[\`supabase-js\`](https://github.com/supabase/supabase-js) supports \`limit()\` but not \`offset()\`.
\`range()\` allows us to accomplish the equivalent logic.
`,
},
]