faqs.ts228 lines · main
1import { someFilter } from '@supabase/sql-to-rest'
2import { stripIndent } from 'common-tags'
3
4import { ResultBundle } from './util'
5
6export type Faq = {
7 id: string
8 condition: (result: ResultBundle) => boolean
9 question: string
10 answer: string
11}
12
13export const faqs: Faq[] = [
14 {
15 id: 'what-is-curl',
16 condition: (result) => result.language === 'curl',
17 question: 'What is `curl`?',
18 answer: stripIndent`
19 \`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.
20
21 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.
22 `,
23 },
24 {
25 id: 'what-is-http',
26 condition: (result) => result.language === 'http',
27 question: 'What format is this?',
28 answer: stripIndent`
29 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.
30 `,
31 },
32 {
33 id: 'what-is-briven-js',
34 condition: (result) => result.language === 'js',
35 question: 'What library is this?',
36 answer: stripIndent`
37 This snippet uses [\`briven-js\`](https://github.com/supabase/supabase-js), a JavaScript/TypeScript client that provides a convenient SDK wrapper around your project's API.
38
39 See [Installing](/docs/reference/javascript/installing) to get started.
40 `,
41 },
42 {
43 id: 'curl-flags',
44 condition: (result) =>
45 result.language === 'curl' && result.method === 'GET' && result.params.size > 0,
46 question: 'What do `-G` and `-d` do?',
47 answer: stripIndent`
48 In \`curl\`, \`-d\` is short for \`--data-urlencode\` and is typically used to add payload to \`POST\` requests.
49
50 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.
51 `,
52 },
53 {
54 id: 'how-do-aliases-work',
55 condition: ({ statement }) =>
56 // Show this if there is at least one alias
57 statement.targets.some((target) => target.alias),
58 question: 'How do aliases work?',
59 answer: stripIndent`
60 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:
61
62 *Request*
63
64 \`\`\`bash
65 /books?select=myTitle:title
66 \`\`\`
67
68 *Response*
69 \`\`\`json
70 [
71 {
72 "myTitle": "The Cheese Tax"
73 }
74 ]
75 \`\`\`
76
77 `,
78 },
79 {
80 id: 'why-alias-lower-case',
81 condition: ({ statement }) =>
82 // Show this if there is at least one alias and no aliases have capital letters
83 statement.targets.some((target) => target.alias) &&
84 !statement.targets.some(
85 (target) => target.alias && target.alias !== target.alias.toLowerCase()
86 ),
87 question: 'Why is my alias lower case?',
88 answer: stripIndent`
89 Postgres converts all SQL identifiers to lowercase by default. To keep casing when converting from SQL, wrap your alias in double quotes:
90
91 \`\`\`sql
92 select
93 title as "myTitle"
94 from
95 books
96 \`\`\`
97 `,
98 },
99 {
100 id: 'how-does-and-work',
101 condition: ({ statement }) =>
102 // Show this if there is at least one `AND` operator
103 !!statement.filter &&
104 statement.filter.type === 'logical' &&
105 statement.filter.operator === 'and',
106 question: 'How does the `AND` operator work?',
107 answer: stripIndent`
108 PostgREST treats each \`AND\` expression as a separate query parameter.
109
110 For example the following SQL:
111
112 \`\`\`sql
113 select
114 *
115 from
116 books
117 where
118 description ilike '%cheese%' and
119 pages > 100
120 \`\`\`
121
122 is equivalent to this API request:
123
124 \`\`\`bash
125 /books?description=ilike.*cheese*&pages=gt.100
126 \`\`\`
127
128 There are exceptions when you have nested \`AND\` expressions, but otherwise this provides an API most consistent with other REST APIs.
129 `,
130 },
131 {
132 id: 'how-do-joins-work',
133 condition: ({ statement }) =>
134 // Show this if there is at least one resource embedding
135 statement.targets.some((target) => target.type === 'embedded-target'),
136 question: 'How do joins work?',
137 answer: stripIndent`
138 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:
139
140 \`\`\`bash
141 /books?select=authors(name)
142 \`\`\`
143
144 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.
145
146 Some important notes about resource embeddings:
147 - 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
148 - Because of this, not all joins are supported - only those that join on the foreign key columns
149 - Joins are \`LEFT\` by default. To perform an \`INNER\` join, add \`!inner\` to the embedded resource:
150 \`\`\`bash
151 /books?select=author!inner(name)
152 \`\`\`
153 PostgREST only supports \`LEFT\` and \`INNER\` joins.
154 - Resource embeddings are nested by default:
155
156 *Request*
157
158 \`\`\`bash
159 /books?select=title,author(name)
160 \`\`\`
161
162 *Response*
163
164 \`\`\`json
165 {
166 "title": "The Cheese Tax",
167 "author": {
168 "name": "Bobby Bobson"
169 }
170 }
171 \`\`\`
172
173 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):
174
175 *Request*
176
177 \`\`\`bash
178 /books?select=...author(authorName:name)
179 \`\`\`
180
181 *Response*
182
183 \`\`\`json
184 {
185 "authorName": "Bobby Bobson"
186 }
187 \`\`\`
188
189 Note that we also aliased the author's name as \`authorName\` for better clarity (otherwise it would have been just \`name\`).
190
191 Only many-to-one and one-to-one relationships support the spread syntax.
192
193 `,
194 },
195 {
196 id: 'why-percent-sign-conversion',
197 condition: ({ type, statement }) =>
198 // Show this if this is an HTTP render, there is a like/ilike filter, and at least one filter contains '%' character
199 type === 'http' &&
200 !!statement.filter &&
201 someFilter(
202 statement.filter,
203 (filter) =>
204 ['like', 'ilike'].includes(filter.operator) &&
205 typeof filter.value === 'string' &&
206 filter.value.includes('%')
207 ),
208 question: 'Why is `%` getting converted to `*`?',
209 answer: stripIndent`
210 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.
211
212 `,
213 },
214 {
215 id: 'why-range-briven-js',
216 condition: (result) =>
217 // Show this if viewing the JS code and there is both a limit and offset
218 result.language === 'js' &&
219 result.statement.limit?.count !== undefined &&
220 result.statement.limit.offset !== undefined,
221 question: 'Why `range()` instead of `limit()` and `offset()`?',
222 answer: stripIndent`
223 [\`briven-js\`](https://github.com/supabase/supabase-js) supports \`limit()\` but not \`offset()\`.
224
225 \`range()\` allows us to accomplish the equivalent logic.
226 `,
227 },
228]