mirror of
https://github.com/supabase/supabase.git
synced 2026-10-10 11:55:05 +03:00
* 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>
228 lines
7.7 KiB
TypeScript
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.
|
|
`,
|
|
},
|
|
]
|