SQLEditor.queries.ts 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603
  1. import type { SQLTemplate } from './SQLEditor.types'
  2. import { DOCS_URL } from '@/lib/constants'
  3. export const SQL_TEMPLATES: SQLTemplate[] = [
  4. {
  5. id: 1,
  6. type: 'template',
  7. title: 'Create table',
  8. description: 'Basic table template. Change "table_name" to the name you prefer.',
  9. sql: `create table table_name (
  10. id bigint generated by default as identity primary key,
  11. inserted_at timestamp with time zone default timezone('utc'::text, now()) not null,
  12. updated_at timestamp with time zone default timezone('utc'::text, now()) not null,
  13. data jsonb,
  14. name text
  15. );`,
  16. },
  17. {
  18. id: 2,
  19. type: 'template',
  20. title: 'Add view',
  21. description:
  22. 'Template to add a view. Make sure to change the table and column names to ones that already exist.',
  23. sql: `CREATE VIEW countries_view AS
  24. SELECT id, continent
  25. FROM countries;`,
  26. },
  27. {
  28. id: 3,
  29. type: 'template',
  30. title: 'Add column',
  31. description: 'Template to add a column. Make sure to change the name and type.',
  32. sql: `alter table table_name
  33. add column new_column_name data_type;`,
  34. },
  35. {
  36. id: 4,
  37. type: 'template',
  38. title: 'Add comments',
  39. description: 'Templates to add a comment to either a table or a column.',
  40. sql: `comment on table table_name is 'Table description';
  41. comment on column table_name.column_name is 'Column description';`,
  42. },
  43. {
  44. id: 5,
  45. type: 'template',
  46. title: 'Show extensions',
  47. description: 'Get a list of extensions in your database and status.',
  48. sql: `select
  49. name, comment, default_version, installed_version
  50. from
  51. pg_available_extensions
  52. order by
  53. name asc;`,
  54. },
  55. {
  56. id: 6,
  57. type: 'template',
  58. title: 'Show version',
  59. description: 'Get your Postgres version.',
  60. sql: `select * from
  61. (select version()) as version,
  62. (select current_setting('server_version_num')) as version_number;`,
  63. },
  64. {
  65. id: 7,
  66. type: 'template',
  67. title: 'Show active connections',
  68. description: 'Get the number of active and max connections.',
  69. sql: `select * from
  70. (select count(pid) as active_connections FROM pg_stat_activity where state = 'active') active_connections,
  71. (select setting as max_connections from pg_settings where name = 'max_connections') max_connections;`,
  72. },
  73. {
  74. id: 8,
  75. type: 'template',
  76. title: 'Automatically update timestamps',
  77. description: 'Update a column timestamp on every update.',
  78. sql: `
  79. create extension if not exists moddatetime schema extensions;
  80. -- assuming the table name is "todos", and a timestamp column "updated_at"
  81. -- this trigger will set the "updated_at" column to the current timestamp for every update
  82. create trigger
  83. handle_updated_at before update
  84. on todos
  85. for each row execute
  86. procedure moddatetime(updated_at);
  87. `.trim(),
  88. },
  89. {
  90. id: 9,
  91. type: 'template',
  92. title: 'Increment field value',
  93. description: 'Update a field with incrementing value using a function.',
  94. sql: `
  95. create function increment(row_id int)
  96. returns void as
  97. $$
  98. update table_name
  99. set field_name = field_name + 1
  100. where id = row_id;
  101. $$
  102. language sql volatile;
  103. -- you can call the function from your browser with briven-js
  104. -- const { data, error } = await briven.rpc('increment', { row_id: 2 })
  105. `.trim(),
  106. },
  107. {
  108. id: 10,
  109. type: 'template',
  110. title: 'pg_stat_statements report',
  111. description: 'Select from pg_stat_statements and view recent queries',
  112. sql: `-- pg_stat_statements report
  113. -- A limit of 100 has been added below
  114. select
  115. auth.rolname,
  116. statements.query,
  117. statements.calls,
  118. -- -- Postgres 13, 14
  119. statements.total_exec_time + statements.total_plan_time as total_time,
  120. statements.min_exec_time + statements.min_plan_time as min_time,
  121. statements.max_exec_time + statements.max_plan_time as max_time,
  122. statements.mean_exec_time + statements.mean_plan_time as mean_time,
  123. -- -- Postgres <= 12
  124. -- total_time,
  125. -- min_time,
  126. -- max_time,
  127. -- mean_time,
  128. statements.rows / statements.calls as avg_rows,
  129. statements.wal_bytes,
  130. statements.wal_records
  131. from pg_stat_statements as statements
  132. inner join pg_authid as auth on statements.userid = auth.oid
  133. order by
  134. total_time desc
  135. limit
  136. 100;`,
  137. },
  138. {
  139. id: 11,
  140. type: 'quickstart',
  141. title: 'Colors',
  142. description: 'Create a table with a list of colors and their hex values.',
  143. sql: `-- Information from Wikipedia "List of Colors"
  144. CREATE TYPE public.color_source AS ENUM (
  145. '99COLORS_NET',
  146. 'ART_PAINTS_YG07S',
  147. 'BYRNE',
  148. 'CRAYOLA',
  149. 'CMYK_COLOR_MODEL',
  150. 'COLORCODE_IS',
  151. 'COLORHEXA',
  152. 'COLORXS',
  153. 'CORNELL_UNIVERSITY',
  154. 'COLUMBIA_UNIVERSITY',
  155. 'DUKE_UNIVERSITY',
  156. 'ENCYCOLORPEDIA_COM',
  157. 'ETON_COLLEGE',
  158. 'FANTETTI_AND_PETRACCHI',
  159. 'FINDTHEDATA_COM',
  160. 'FERRARIO_1919',
  161. 'FEDERAL_STANDARD_595',
  162. 'FLAG_OF_INDIA',
  163. 'FLAG_OF_SOUTH_AFRICA',
  164. 'GLAZEBROOK_AND_BALDRY',
  165. 'GOOGLE',
  166. 'HEXCOLOR_CO',
  167. 'ISCC_NBS',
  168. 'KELLY_MOORE',
  169. 'MATTEL',
  170. 'MAERZ_AND_PAUL',
  171. 'MILK_PAINT',
  172. 'MUNSELL_COLOR_WHEEL',
  173. 'NATURAL_COLOR_SYSTEM',
  174. 'PANTONE',
  175. 'PLOCHERE',
  176. 'POURPRE_COM',
  177. 'RAL',
  178. 'RESENE',
  179. 'RGB_COLOR_MODEL',
  180. 'THOM_POOLE',
  181. 'UNIVERSITY_OF_ALABAMA',
  182. 'UNIVERSITY_OF_CALIFORNIA_DAVIS',
  183. 'UNIVERSITY_OF_CAMBRIDGE',
  184. 'UNIVERSITY_OF_NORTH_CAROLINA',
  185. 'UNIVERSITY_OF_TEXAS_AT_AUSTIN',
  186. 'X11_WEB',
  187. 'XONA_COM'
  188. );
  189. create table public.colors (
  190. id bigint generated by default as identity primary key,
  191. name text,
  192. hex text not null,
  193. red int2,
  194. green int2,
  195. blue int2,
  196. hue int2,
  197. sat_hsl int2,
  198. light_hsl int2,
  199. sat_hsv int2,
  200. val_hsv int2,
  201. source color_source
  202. );
  203. comment on table colors is 'Full list of colors (based on various sources)';
  204. comment on column colors.name is 'Name of the color';
  205. comment on column colors.hex is 'Hex tripliets of the color for HTML web colors';
  206. comment on column colors.red is 'Red in RGB (%)';
  207. comment on column colors.green is 'Green in RGB (%)';
  208. comment on column colors.blue is 'Blue in RGB (%)';
  209. comment on column colors.hue is 'Hue in HSL (°)';
  210. comment on column colors.sat_hsl is 'Saturation in HSL (%)';
  211. comment on column colors.light_hsl is 'Light in HSL (%)';
  212. comment on column colors.sat_hsv is 'Saturation in HSV (%)';
  213. comment on column colors.val_hsv is 'Value in HSV (%)';
  214. comment on column colors.source is 'Source of information on the color';
  215. insert into public.colors (name, hex, red, green, blue, hue, sat_hsl, light_hsl, sat_hsv, val_hsv, source) values
  216. ('Absolute Zero', '#0048BA', 0, 28, 73, 217, 100, 37, 100, 73, 'CRAYOLA'),
  217. ('Acid green', '#B0BF1A', 69, 75, 10, 65, 76, 43, 76, 75, 'ART_PAINTS_YG07S'),
  218. ('Aero', '#7CB9E8', 49, 73, 91, 206, 70, 70, 47, 91, 'MAERZ_AND_PAUL'),
  219. ('African violet', '#B284BE', 70, 52, 75, 288, 31, 63, 31.5, '75', 'PANTONE'),
  220. ('Air superiority blue', '#72A0C1', 45, 63, 76, 205, 39, 60, 41, 76, 'FEDERAL_STANDARD_595'),
  221. ('Alice blue', '#F0F8FF', 94, 97, 100, 208, 100, 97, 6, 100, 'X11_WEB'),
  222. ('Alizarin', '#DB2D43', 86, 18, 26, 352, 71, 52, 79, 86, 'MAERZ_AND_PAUL'),
  223. ('Alloy orange', '#C46210', 77, 38, 6, 27, 85, 42, 92, 77, 'CRAYOLA'),
  224. ('Almond', '#EED9C4', 93, 85, 77, 30, 55, 85, 18, 93, 'CRAYOLA'),
  225. ('Amaranth deep purple', '#9F2B68', 62, 17, 41, 328, 57, 40, 73, 62, 'MAERZ_AND_PAUL'),
  226. ('Amaranth pink', '#F19CBB', 95, 61, 73, 338, 75, 78, 35, 95, 'MAERZ_AND_PAUL'),
  227. ('Amaranth purple', '#AB274F', 67, 15, 31, 342, 63, 41, 77, 67, 'MAERZ_AND_PAUL'),
  228. ('Amazon', '#3B7A57', 23, 48, 34, 147, 35, 36, 52, 48, 'XONA_COM'),
  229. ('Amber', '#FFBF00', 100, 75, 0, 45, 100, 50, 100, 100, 'RGB_COLOR_MODEL'),
  230. ('Amethyst', '#9966CC', 60, 40, 80, 270, 50, 60, 50, 80, 'X11_WEB'),
  231. ('Android green', '#3DDC84', 24, 86, 53, 148, 69, 55, 72, 86, 'GOOGLE'),
  232. ('Antique brass', '#C88A65', 78, 54, 40, 22, 47, 59, 49, 78, 'CRAYOLA'),
  233. ('Antique bronze', '#665D1E', 40, 36, 12, 53, 55, 26, 71, 40, 'ISCC_NBS'),
  234. ('Antique fuchsia', '#915C83', 57, 36, 51, 316, 22, 46, 37, 57, 'PLOCHERE'),
  235. ('Antique ruby', '#841B2D', 52, 11, 18, 350, 66, 31, 80, 52, 'ISCC_NBS'),
  236. ('Antique white', '#FAEBD7', 98, 92, 84, 34, 78, 91, 14, 98, 'X11_WEB'),
  237. ('Apricot', '#FBCEB1', 98, 81, 69, 24, 90, 84, 29, 98, 'MAERZ_AND_PAUL'),
  238. ('Aqua', '#00FFFF', 0, 100, 100, 180, 100, 50, 100, 100, 'X11_WEB'),
  239. ('Aquamarine', '#7FFFD4', 50, 100, 83, 160, 100, 75, 50, 100, 'X11_WEB'),
  240. ('Arctic lime', '#D0FF14', 82, 100, 8, 72, 100, 54, 92, 100, 'CRAYOLA'),
  241. ('Artichoke green', '#4B6F44', 29, 44, 27, 110, 24, 35, 39, 44, 'PANTONE'),
  242. ('Arylide yellow', '#E9D66B', 91, 84, 42, 51, 74, 67, 54, 91, 'COLORHEXA'),
  243. ('Ash gray', '#B2BEB5', 70, 75, 71, 135, 9, 72, 6, 75, 'ISCC_NBS'),
  244. ('Atomic tangerine', '#FF9966', 100, 60, 40, 20, 100, 70, 60, 100, 'CRAYOLA'),
  245. ('Aureolin', '#FDEE00', 99, 93, 0, 56, 100, 50, 100, 99, 'X11_WEB'),
  246. ('Azure', '#007FFF', 0, 50, 100, 210, 100, 50, 100, 100, 'RGB_COLOR_MODEL'),
  247. ('Azure (X11/web color)', '#F0FFFF', 94, 100, 100, 180, 100, 97, 6, 100, 'X11_WEB'),
  248. ('Baby blue', '#89CFF0', 54, 81, 94, 199, 77, 74, 43, 94, 'MAERZ_AND_PAUL'),
  249. ('Baby blue eyes', '#A1CAF1', 63, 79, 95, 209, 74, 79, 33, 95, 'PLOCHERE'),
  250. ('Baby pink', '#F4C2C2', 96, 76, 76, 0, 69, 86, 20, 96, 'ISCC_NBS'),
  251. ('Baby powder', '#FEFEFA', 100, 100, 98, 60, 67, 99, 2, 100, 'CRAYOLA'),
  252. ('Baker-Miller pink', '#FF91AF', 100, 57, 69, 344, 100, 78, 43, 100, 'BYRNE'),
  253. ('Banana Mania', '#FAE7B5', 98, 91, 71, 43, 87, 85, 28, 98, 'CRAYOLA'),
  254. ('Barbie Pink', '#DA1884', 85, 9, 52, 327, 80, 48, 89, 85, 'MATTEL'),
  255. ('Barn red', '#7C0A02', 49, 4, 1, 4, 97, 25, 98, 49, 'MILK_PAINT'),
  256. ('Battleship grey', '#848482', 52, 52, 51, 60, 1, 51, 2, 52, 'ISCC_NBS'),
  257. ('Beau blue', '#BCD4E6', 74, 83, 90, 206, 46, 82, 18, 90, 'PLOCHERE'),
  258. ('Beaver', '#9F8170', 62, 51, 44, 22, 20, 53, 30, 62, 'CRAYOLA'),
  259. ('Beige', '#F5F5DC', 96, 96, 86, 60, 56, 91, 10, 96, 'X11_WEB'),
  260. ('B''dazzled blue', '#2E5894', 18, 35, 58, 215, 53, 38, 69, 58, 'CRAYOLA'),
  261. ('Big dip o''ruby', '#9C2542', 61, 15, 26, 345, 62, 38, 76, 61, 'CRAYOLA'),
  262. ('Bisque', '#FFE4C4', 100, 89, 77, 33, 100, 88, 23, 100, 'X11_WEB'),
  263. ('Bistre', '#3D2B1F', 24, 17, 12, 24, 33, 18, 49, 24, '99COLORS_NET'),
  264. ('Bistre brown', '#967117', 59, 44, 9, 43, 73, 34, 85, 59, 'ISCC_NBS'),
  265. ('Bitter lemon', '#CAE00D', 79, 88, 5, 66, 89, 47, 94, 88, 'XONA_COM'),
  266. ('Black', '#000000', 0, 0, 0, 0, 0, 0, 0, 0, 'RGB_COLOR_MODEL'),
  267. ('Black bean', '#3D0C02', 24, 5, 1, 10, 94, 12, 97, 24, 'XONA_COM'),
  268. ('Black coral', '#54626F', 33, 38, 44, 209, 14, 38, 24, 44, 'CRAYOLA'),
  269. ('Black olive', '#3B3C36', 23, 24, 21, 70, 5, 22, 10, 24, 'RAL'),
  270. ('Black Shadows', '#BFAFB2', 75, 69, 70, 349, 11, 72, 8, 75, 'CRAYOLA'),
  271. ('Blanched almond', '#FFEBCD', 100, 92, 80, 36, 100, 90, 20, 100, 'X11_WEB'),
  272. ('Blast-off bronze', '#A57164', 65, 44, 39, 12, 27, 52, 39, 65, 'CRAYOLA'),
  273. ('Bleu de France', '#318CE7', 19, 55, 91, 210, 79, 55, 79, 91, 'POURPRE_COM'),
  274. ('Blizzard blue', '#ACE5EE', 67, 90, 93, 188, 66, 80, 28, 93, 'CRAYOLA'),
  275. ('Blood red', '#660000', 40, 0, 0, 0, 100, 20, 100, 40, 'THOM_POOLE'),
  276. ('Blue', '#0000FF', 0, 0, 100, 240, 100, 50, 100, 100, 'X11_WEB'),
  277. ('Blue (Crayola)', '#1F75FE', 12, 46, 100, 217, 99, 56, 88, 100, 'CRAYOLA'),
  278. ('Blue (Munsell)', '#0093AF', 0, 58, 69, 190, 100, 34, 100, 69, 'MUNSELL_COLOR_WHEEL'),
  279. ('Blue (NCS)', '#0087BD', 0, 53, 74, 197, 100, 37, 100, 74, 'NATURAL_COLOR_SYSTEM'),
  280. ('Blue (Pantone)', '#0018A8', 0, 9, 66, 231, 100, 33, 100, 66, 'PANTONE'),
  281. ('Blue (pigment)', '#333399', 20, 20, 60, 240, 50, 40, 67, 60, 'CMYK_COLOR_MODEL'),
  282. ('Blue bell', '#A2A2D0', 64, 64, 82, 240, 33, 73, 22, 82, 'CRAYOLA'),
  283. ('Blue-gray (Crayola)', '#6699CC', 40, 60, 80, 210, 50, 60, 50, 80, 'CRAYOLA'),
  284. ('Blue jeans', '#5DADEC', 36, 68, 93, 206, 79, 65, 61, 93, 'CRAYOLA'),
  285. ('Blue sapphire', '#126180', 7, 38, 50, 197, 75, 29, 86, 50, 'PANTONE'),
  286. ('Blue-violet', '#8A2BE2', 54, 17, 89, 271, 76, 53, 81, 89, 'X11_WEB'),
  287. ('Blue yonder', '#5072A7', 31, 45, 65, 217, 35, 48, 52, 65, 'PANTONE'),
  288. ('Bluetiful', '#3C69E7', 24, 41, 91, 224, 78, 57, 74, 91, 'CRAYOLA'),
  289. ('Blush', '#DE5D83', 87, 36, 51, 342, 66, 62, 58, 87, 'CRAYOLA'),
  290. ('Bole', '#79443B', 47, 27, 23, 9, 34, 35, 51, 47, 'ISCC_NBS'),
  291. ('Bone', '#E3DAC9', 89, 85, 79, 39, 32, 84, 11, 89, 'KELLY_MOORE'),
  292. ('Brick red', '#CB4154', 80, 25, 33, 352, 57, 53, 68, 80, 'CRAYOLA'),
  293. ('Bright lilac', '#D891EF', 85, 57, 94, 285, 75, 75, 39, 94, 'CRAYOLA'),
  294. ('Bright yellow (Crayola)', '#FFAA1D', 100, 67, 11, 37, 100, 56, 89, 100, 'CRAYOLA'),
  295. ('British racing green', '#004225', 0, 26, 15, 154, 100, 13, 100, 26, 'COLORHEXA'),
  296. ('Bronze', '#CD7F32', 80, 50, 20, 30, 61, 50, 76, 80, 'MAERZ_AND_PAUL'),
  297. ('Brown', '#964B00', 59, 29, 0, 30, 100, 29, 100, 59, 'COLORXS'),
  298. ('Brown sugar', '#AF6E4D', 69, 43, 30, 20, 39, 49, 56, 69, 'CRAYOLA'),
  299. ('Bud green', '#7BB661', 48, 71, 38, 102, 37, 55, 47, 71, 'PANTONE'),
  300. ('Buff', '#FFC680', 100, 78, 50, 33, 100, 75, 50, 100, 'MAERZ_AND_PAUL'),
  301. ('Burgundy', '#800020', 50, 0, 13, 345, 100, 25, 100, 50, 'MAERZ_AND_PAUL'),
  302. ('Burlywood', '#DEB887', 87, 72, 53, 34, 57, 70, 39, 87, 'X11_WEB'),
  303. ('Burnished brown', '#A17A74', 63, 48, 45, 8, 19, 54, 28, 63, 'CRAYOLA'),
  304. ('Burnt orange', '#CC5500', 80, 33, 0, 25, 100, 40, 100, 80, 'UNIVERSITY_OF_TEXAS_AT_AUSTIN'),
  305. ('Burnt sienna', '#E97451', 91, 45, 32, 14, 78, 62, 65, 91, 'FERRARIO_1919'),
  306. ('Burnt umber', '#8A3324', 54, 20, 14, 9, 59, 34, 74, 54, 'XONA_COM'),
  307. ('Byzantine', '#BD33A4', 74, 20, 64, 311, 58, 47, 73, 74, 'MAERZ_AND_PAUL'),
  308. ('Byzantium', '#702963', 44, 16, 39, 311, 46, 30, 63, 44, 'ISCC_NBS'),
  309. ('Cadet blue', '#5F9EA0', 37, 62, 63, 182, 26, 50, 41, 63, 'X11_WEB'),
  310. ('Cadet grey', '#91A3B0', 57, 64, 69, 205, 16, 63, 18, 69, 'ISCC_NBS'),
  311. ('Cadmium green', '#006B3C', 0, 42, 24, 154, 100, 21, 100, 42, 'ISCC_NBS'),
  312. ('Cadmium orange', '#ED872D', 93, 53, 18, 28, 84, 55, 81, 93, 'ISCC_NBS'),
  313. ('Café au lait', '#A67B5B', 65, 48, 36, 26, 30, 50, 45, 65, 'ISCC_NBS'),
  314. ('Café noir', '#4B3621', 29, 21, 13, 30, 39, 21, 56, 29, 'ISCC_NBS'),
  315. ('Cambridge blue', '#A3C1AD', 64, 76, 68, 140, 20, 70, 16, 76, 'UNIVERSITY_OF_CAMBRIDGE'),
  316. ('Camel', '#C19A6B', 76, 60, 42, 33, 41, 59, 45, 76, 'ISCC_NBS'),
  317. ('Cameo pink', '#EFBBCC', 94, 73, 80, 340, 62, 84, 22, 94, 'ISCC_NBS'),
  318. ('Canary', '#FFFF99', 100, 100, 60, 60, 100, 80, 40, 100, 'CRAYOLA'),
  319. ('Canary yellow', '#FFEF00', 100, 94, 0, 56, 100, 50, 100, 100, 'CMYK_COLOR_MODEL'),
  320. ('Candy pink', '#E4717A', 89, 44, 48, 355, 68, 67, 50, 89, 'ISCC_NBS'),
  321. ('Cardinal', '#C41E3A', 77, 12, 23, 350, 74, 44, 85, 77, 'MAERZ_AND_PAUL'),
  322. ('Caribbean green', '#00CC99', 0, 80, 60, 165, 100, 40, 100, 80, 'CRAYOLA'),
  323. ('Carmine', '#960018', 59, 0, 9, 350, 100, 29, 100, 59, 'POURPRE_COM'),
  324. ('Carmine (M&P)', '#D70040', 84, 0, 25, 342, 100, 42, 100, 84, 'MAERZ_AND_PAUL'),
  325. ('Carnation pink', '#FFA6C9', 100, 65, 79, 336, 100, 83, 35, 100, 'CRAYOLA'),
  326. ('Carnelian', '#B31B1B', 70, 11, 11, 0, 74, 40, 85, 70, 'CORNELL_UNIVERSITY'),
  327. ('Carolina blue', '#56A0D3', 34, 63, 83, 204, 59, 58, 59, 83, 'UNIVERSITY_OF_NORTH_CAROLINA'),
  328. ('Carrot orange', '#ED9121', 93, 57, 13, 33, 85, 53, 86, 93, 'MAERZ_AND_PAUL'),
  329. ('Catawba', '#703642', 44, 21, 26, 348, 35, 33, 52, 44, 'MAERZ_AND_PAUL'),
  330. ('Cedar Chest', '#C95A49', 79, 35, 29, 8, 54, 54, 64, 79, 'CRAYOLA'),
  331. ('Celadon', '#ACE1AF', 67, 88, 69, 123, 47, 78, 24, 88, 'ENCYCOLORPEDIA_COM'),
  332. ('Celeste', '#B2FFFF', 70, 100, 100, 180, 100, 85, 30, 100, 'FANTETTI_AND_PETRACCHI'),
  333. ('Cerise', '#DE3163', 87, 19, 39, 343, 72, 53, 78, 87, 'MAERZ_AND_PAUL'),
  334. ('Cerulean', '#007BA7', 0, 48, 65, 196, 100, 33, 100, 65, 'MAERZ_AND_PAUL'),
  335. ('Cerulean blue', '#2A52BE', 16, 32, 75, 224, 64, 46, 78, 75, 'MAERZ_AND_PAUL'),
  336. ('Cerulean frost', '#6D9BC3', 43, 61, 76, 208, 42, 60, 44, 76, 'CRAYOLA'),
  337. ('Cerulean (Crayola)', '#1DACD6', 11, 67, 84, 194, 76, 48, 86, 84, 'CRAYOLA'),
  338. ('Cerulean (RGB)', '#0040FF', 0, 25, 100, 225, 100, 50, 100, 100, null),
  339. ('Champagne', '#F7E7CE', 97, 91, 81, 37, 72, 89, 17, 97, 'MAERZ_AND_PAUL'),
  340. ('Champagne pink', '#F1DDCF', 95, 87, 81, 25, 55, 88, 14, 95, 'PANTONE'),
  341. ('Charcoal', '#36454F', 21, 27, 31, 204, 19, 26, 32, 31, 'ISCC_NBS'),
  342. ('Charm pink', '#E68FAC', 90, 56, 67, 340, 64, 73, 38, 90, 'PLOCHERE'),
  343. ('Chartreuse (web)', '#80FF00', 50, 100, 0, 90, 100, 50, 100, 100, 'RGB_COLOR_MODEL'),
  344. ('Cherry blossom pink', '#FFB7C5', 100, 72, 77, 348, 100, 86, 28, 100, 'MAERZ_AND_PAUL'),
  345. ('Chestnut', '#954535', 58, 27, 21, 10, 48, 40, 64, 58, 'MAERZ_AND_PAUL'),
  346. ('Chili red', '#E23D28', 89, 24, 16, 5, 76, 52, 183, 125, 'FLAG_OF_SOUTH_AFRICA'),
  347. ('China pink', '#DE6FA1', 87, 44, 63, 333, 63, 65, 50, 87, 'PLOCHERE'),
  348. ('Chinese red', '#AA381E', 67, 22, 12, 11, 70, 39, 82, 67, 'ISCC_NBS'),
  349. ('Chinese violet', '#856088', 52, 38, 53, 296, 17, 46, 29, 53, 'PANTONE'),
  350. ('Chinese yellow', '#FFB200', 100, 70, 0, 42, 100, 50, 100, 100, 'ISCC_NBS'),
  351. ('Chocolate (traditional)', '#7B3F00', 48, 25, 0, 31, 100, 24, 100, 48, 'MAERZ_AND_PAUL'),
  352. ('Chocolate (web)', '#D2691E', 82, 41, 12, 25, 75, 47, 86, 82, 'X11_WEB'),
  353. ('Cinereous', '#98817B', 60, 51, 48, 12, 12, 54, 19, 60, 'MAERZ_AND_PAUL'),
  354. ('Cinnabar', '#E34234', 89, 26, 20, 5, 76, 55, 77, 89, 'MAERZ_AND_PAUL'),
  355. ('Cinnamon Satin', '#CD607E', 80, 38, 49, 343, 52, 59, 53, 80, 'CRAYOLA'),
  356. ('Citrine', '#E4D00A', 89, 82, 4, 54, 92, 47, 96, 89, 'MAERZ_AND_PAUL'),
  357. ('Citron', '#9FA91F', 62, 66, 12, 64, 69, 39, 82, 66, 'XONA_COM'),
  358. ('Claret', '#7F1734', 50, 9, 20, 343, 69, 29, 82, 50, 'XONA_COM'),
  359. ('Coffee', '#6F4E37', 44, 31, 22, 25, 34, 33, 50, 44, 'ISCC_NBS'),
  360. ('Columbia Blue', '#B9D9EB', 73, 85, 92, 202, 56, 82, 21, 92, 'COLUMBIA_UNIVERSITY'),
  361. ('Congo pink', '#F88379', 97, 51, 47, 5, 90, 72, 51, 97, 'ISCC_NBS'),
  362. ('Cool grey', '#8C92AC', 55, 57, 67, 229, 16, 61, 19, 67, 'ISCC_NBS'),
  363. ('Copper', '#B87333', 72, 45, 20, 29, 57, 46, 72, 72, 'MAERZ_AND_PAUL'),
  364. ('Copper (Crayola)', '#DA8A67', 85, 54, 40, 18, 61, 63, 53, 85, 'CRAYOLA'),
  365. ('Copper penny', '#AD6F69', 68, 44, 41, 5, 29, 55, 39, 68, 'CRAYOLA'),
  366. ('Copper red', '#CB6D51', 80, 43, 32, 14, 54, 56, 60, 80, 'ISCC_NBS'),
  367. ('Copper rose', '#996666', 60, 40, 40, 0, 20, 50, 33, 60, '99COLORS_NET'),
  368. ('Coquelicot', '#FF3800', 100, 22, 0, 13, 100, 50, 100, 100, 'COLORHEXA'),
  369. ('Coral', '#FF7F50', 100, 50, 31, 16, 100, 66, 69, 100, 'X11_WEB'),
  370. ('Coral pink', '#F88379', 97, 51, 47, 5, 90, 72, 51, 97, 'ISCC_NBS'),
  371. ('Cordovan', '#893F45', 54, 25, 27, 355, 37, 39, 54, 54, 'PANTONE'),
  372. ('Corn', '#FBEC5D', 98, 93, 36, 54, 95, 68, 63, 98, 'MAERZ_AND_PAUL'),
  373. ('Cornflower blue', '#6495ED', 39, 58, 93, 219, 79, 66, 58, 93, 'X11_WEB'),
  374. ('Cornsilk', '#FFF8DC', 100, 97, 86, 48, 100, 93, 14, 100, 'X11_WEB'),
  375. ('Cosmic cobalt', '#2E2D88', 18, 18, 53, 241, 50, 36, 67, 53, 'CRAYOLA'),
  376. ('Cosmic latte', '#FFF8E7', 100, 97, 91, 43, 100, 95, 9, 100, 'GLAZEBROOK_AND_BALDRY'),
  377. ('Coyote brown', '#81613C', 51, 38, 24, 32, 37, 37, 52, 51, 'COLORCODE_IS'),
  378. ('Cotton candy', '#FFBCD9', 100, 74, 85, 334, 100, 87, 26, 100, 'CRAYOLA'),
  379. ('Cream', '#FFFDD0', 100, 99, 82, 57, 100, 91, 18, 100, 'MAERZ_AND_PAUL'),
  380. ('Crimson', '#DC143C', 86, 8, 24, 348, 83, 47, 91, 86, 'X11_WEB'),
  381. ('Crimson (UA)', '#9E1B32', 62, 11, 20, 349, 71, 36, 83, 62, 'UNIVERSITY_OF_ALABAMA'),
  382. ('Cultured Pearl', '#F5F5F5', 96, 96, 96, 0, 0, 96, 0, 96, 'CRAYOLA'),
  383. ('Cyan', '#00FFFF', 0, 100, 100, 180, 100, 50, 100, 100, 'X11_WEB'),
  384. ('Cyan (process)', '#00B7EB', 0, 72, 92, 193, 100, 46, 100, 92, 'CMYK_COLOR_MODEL'),
  385. ('Cyber grape', '#58427C', 35, 26, 49, 263, 31, 37, 47, 49, 'CRAYOLA'),
  386. ('Cyber yellow', '#FFD300', 100, 83, 0, 50, 100, 50, 100, 100, 'PANTONE'),
  387. ('Cyclamen', '#F56FA1', 96, 44, 63, 338, 87, 70, 54, 96, 'CRAYOLA'),
  388. ('Dandelion', '#FED85D', 100, 85, 36, 46, 99, 68, 63, 100, 'CRAYOLA'),
  389. ('Dark brown', '#654321', 40, 26, 13, 30, 51, 26, 67, 40, 'X11_WEB'),
  390. ('Dark byzantium', '#5D3954', 36, 22, 33, 315, 24, 29, 39, 36, 'ISCC_NBS'),
  391. ('Dark cyan', '#008B8B', 0, 55, 55, 180, 100, 27, 100, 55, 'X11_WEB'),
  392. ('Dark electric blue', '#536878', 33, 41, 47, 206, 18, 40, 31, 47, 'ISCC_NBS'),
  393. ('Dark goldenrod', '#B8860B', 72, 53, 4, 43, 89, 38, 94, 72, 'X11_WEB'),
  394. ('Dark green (X11)', '#006400', 0, 39, 0, 120, 100, 20, 100, 39, 'X11_WEB'),
  395. ('Dark jungle green', '#1A2421', 10, 14, 13, 162, 16, 12, 28, 14, 'ISCC_NBS'),
  396. ('Dark khaki', '#BDB76B', 74, 72, 42, 56, 38, 58, 43, 74, 'X11_WEB'),
  397. ('Dark lava', '#483C32', 28, 24, 20, 27, 18, 24, 31, 28, 'ISCC_NBS'),
  398. ('Dark liver (horses)', '#543D37', 33, 24, 22, 12, 21, 27, 35, 33, 'UNIVERSITY_OF_CALIFORNIA_DAVIS'),
  399. ('Dark magenta', '#8B008B', 55, 0, 55, 300, 100, 27, 100, 55, 'X11_WEB'),
  400. ('Dark olive green', '#556B2F', 33, 42, 18, 82, 39, 30, 56, 42, 'X11_WEB'),
  401. ('Dark orange', '#FF8C00', 100, 55, 0, 33, 100, 50, 100, 100, 'X11_WEB'),
  402. ('Dark orchid', '#9932CC', 60, 20, 80, 280, 61, 50, 75, 80, 'X11_WEB'),
  403. ('Dark purple', '#301934', 19, 10, 20, 291, 35, 15, 51, 20, 'ISCC_NBS'),
  404. ('Dark red', '#8B0000', 55, 0, 0, 0, 100, 27, 100, 55, 'X11_WEB'),
  405. ('Dark salmon', '#E9967A', 91, 59, 48, 15, 72, 70, 48, 91, 'X11_WEB'),
  406. ('Dark sea green', '#8FBC8F', 56, 74, 56, 120, 25, 65, 24, 74, 'X11_WEB'),
  407. ('Dark sienna', '#3C1414', 24, 8, 8, 0, 50, 16, 67, 24, 'ISCC_NBS'),
  408. ('Dark sky blue', '#8CBED6', 55, 75, 84, 199, 47, 69, 35, 84, 'PANTONE'),
  409. ('Dark slate blue', '#483D8B', 28, 24, 55, 248, 39, 39, 56, 55, 'X11_WEB'),
  410. ('Dark slate gray', '#2F4F4F', 18, 31, 31, 180, 25, 25, 41, 31, 'X11_WEB'),
  411. ('Dark spring green', '#177245', 9, 45, 27, 150, 66, 27, 80, 45, 'X11_WEB'),
  412. ('Dark turquoise', '#00CED1', 0, 81, 82, 181, 100, 41, 100, 82, 'X11_WEB'),
  413. ('Dark violet', '#9400D3', 58, 0, 83, 282, 100, 41, 100, 83, 'X11_WEB'),
  414. ('Davy''s grey', '#555555', 33, 33, 33, 0, 0, 33, 0, 33, 'ISCC_NBS'),
  415. ('Deep cerise', '#DA3287', 85, 20, 53, 330, 69, 53, 77, 85, 'CRAYOLA'),
  416. ('Deep champagne', '#FAD6A5', 98, 84, 65, 35, 90, 81, 34, 98, 'ISCC_NBS'),
  417. ('Deep chestnut', '#B94E48', 73, 31, 28, 3, 45, 50, 61, 73, 'CRAYOLA'),
  418. ('Deep jungle green', '#004B49', 0, 29, 29, 178, 100, 15, 100, 29, 'ISCC_NBS'),
  419. ('Deep pink', '#FF1493', 100, 8, 58, 328, 100, 54, 92, 100, 'X11_WEB'),
  420. ('Deep saffron', '#FF9933', 100, 60, 20, 30, 100, 60, 80, 100, 'FLAG_OF_INDIA'),
  421. ('Deep sky blue', '#00BFFF', 0, 75, 100, 195, 100, 50, 100, 100, 'X11_WEB'),
  422. ('Deep Space Sparkle', '#4A646C', 29, 39, 42, 194, 19, 36, 31, 42, 'CRAYOLA'),
  423. ('Deep taupe', '#7E5E60', 49, 37, 38, 356, 15, 43, 25, 49, 'PANTONE'),
  424. ('Denim', '#1560BD', 8, 38, 74, 213, 80, 41, 89, 74, 'CRAYOLA'),
  425. ('Denim blue', '#2243B6', 13, 26, 71, 227, 69, 42, 81, 71, 'CRAYOLA'),
  426. ('Desert', '#C19A6B', 76, 60, 42, 33, 41, 59, 45, 76, 'ISCC_NBS'),
  427. ('Desert sand', '#EDC9AF', 93, 79, 69, 25, 63, 81, 26, 93, 'CRAYOLA'),
  428. ('Dim gray', '#696969', 41, 41, 41, 0, 0, 41, 0, 41, 'X11_WEB'),
  429. ('Dodger blue', '#1E90FF', 12, 56, 100, 210, 100, 56, 88, 100, 'X11_WEB'),
  430. ('Drab dark brown', '#4A412A', 29, 25, 16, 43, 28, 23, 43, 29, 'PANTONE'),
  431. ('Duke blue', '#00009C', 0, 0, 61, 240, 100, 31, 100, 61, 'DUKE_UNIVERSITY'),
  432. ('Dutch white', '#EFDFBB', 94, 87, 73, 42, 62, 84, 22, 94, 'RESENE'),
  433. ('Ebony', '#555D50', 33, 36, 31, 97, 8, 34, 14, 36, 'MAERZ_AND_PAUL'),
  434. ('Ecru', '#C2B280', 76, 70, 50, 45, 35, 63, 34, 76, 'ISCC_NBS'),
  435. ('Eerie black', '#1B1B1B', 11, 11, 11, 0, 0, 11, 0, 11, 'CRAYOLA'),
  436. ('Eggplant', '#614051', 38, 25, 32, 329, 21, 32, 34, 38, 'CRAYOLA'),
  437. ('Eggshell', '#F0EAD6', 94, 92, 84, 46, 46, 89, 11, 94, 'ISCC_NBS'),
  438. ('Electric lime', '#CCFF00', 80, 100, 0, 72, 100, 50, 100, 100, 'CRAYOLA'),
  439. ('Electric purple', '#BF00FF', 75, 0, 100, 285, 100, 50, 100, 100, 'X11_WEB'),
  440. ('Electric violet', '#8F00FF', 56, 0, 100, 274, 100, 50, 100, 100, 'ISCC_NBS'),
  441. ('Emerald', '#50C878', 31, 78, 47, 140, 52, 55, 60, 78, 'MAERZ_AND_PAUL'),
  442. ('Eminence', '#6C3082', 42, 19, 51, 284, 46, 35, 63, 51, 'XONA_COM'),
  443. ('English lavender', '#B48395', 71, 51, 58, 338, 25, 61, 27, 71, 'PANTONE'),
  444. ('English red', '#AB4B52', 67, 29, 32, 356, 39, 48, 56, 67, 'ISCC_NBS'),
  445. ('English vermillion', '#CC474B', 80, 28, 29, 358, 57, 54, 65, 80, 'CRAYOLA'),
  446. ('English violet', '#563C5C', 34, 24, 36, 289, 21, 30, 35, 36, 'ISCC_NBS'),
  447. ('Erin', '#00FF40', 0, 100, 25, 135, 100, 50, 100, 100, 'MAERZ_AND_PAUL'),
  448. ('Eton blue', '#96C8A2', 59, 78, 64, 134, 31, 69, 25, 78, 'ETON_COLLEGE'),
  449. ('Fallow', '#C19A6B', 76, 60, 42, 33, 41, 59, 45, 76, 'ISCC_NBS'),
  450. ('Falu red', '#801818', 50, 9, 9, 0, 68, 30, 81, 50, 'COLORHEXA'),
  451. ('Fandango', '#B53389', 71, 20, 54, 320, 56, 46, 72, 71, 'MAERZ_AND_PAUL'),
  452. ('Fandango pink', '#DE5285', 87, 32, 52, 338, 68, 60, 63, 87, 'PANTONE'),
  453. ('Fawn', '#E5AA70', 90, 67, 44, 30, 69, 67, 51, 90, 'X11_WEB'),
  454. ('Fern green', '#4F7942', 31, 47, 26, 106, 29, 37, 45, 47, 'MAERZ_AND_PAUL'),
  455. ('Field drab', '#6C541E', 42, 33, 12, 42, 57, 27, 72, 42, 'ISCC_NBS'),
  456. ('Fiery rose', '#FF5470', 100, 33, 44, 350, 100, 67, 67, 100, 'CRAYOLA'),
  457. ('Finn', '#683068', 41, 19, 41, 300, 37, 30, 54, 41, 'HEXCOLOR_CO'),
  458. ('Firebrick', '#B22222', 70, 13, 13, 0, 68, 42, 81, 70, 'X11_WEB'),
  459. ('Fire engine red', '#CE2029', 81, 13, 16, 357, 73, 47, 84, 81, 'FINDTHEDATA_COM'),
  460. ('Flame', '#E25822', 89, 35, 13, 17, 77, 51, 85, 89, 'ISCC_NBS'),
  461. ('Flax', '#EEDC82', 93, 86, 51, 50, 76, 72, 45, 93, 'MAERZ_AND_PAUL'),
  462. ('Flirt', '#A2006D', 64, 0, 43, 320, 100, 32, 100, 64, 'XONA_COM'),
  463. ('Floral white', '#FFFAF0', 100, 98, 94, 40, 100, 97, 6, 100, 'X11_WEB'),
  464. ('Forest green (web)', '#228B22', 13, 55, 13, 120, 61, 34, 76, 55, 'X11_WEB'),
  465. ('French beige', '#A67B5B', 65, 48, 36, 26, 30, 50, 45, 65, 'ISCC_NBS'),
  466. ('French bistre', '#856D4D', 52, 43, 30, 34, 27, 41, 42, 52, 'POURPRE_COM'),
  467. ('French blue', '#0072BB', 0, 45, 73, 203, 100, 37, 100, 73, 'MAERZ_AND_PAUL'),
  468. ('French fuchsia', '#FD3F92', 99, 25, 57, 334, 98, 62, 75, 99, 'POURPRE_COM'),
  469. ('French lilac', '#86608E', 53, 38, 56, 290, 19, 47, 32, 56, 'ISCC_NBS'),
  470. ('French lime', '#9EFD38', 62, 99, 22, 89, 98, 61, 78, 99, 'POURPRE_COM'),
  471. ('French mauve', '#D473D4', 83, 45, 83, 300, 53, 64, 46, 83, 'POURPRE_COM'),
  472. ('French pink', '#FD6C9E', 99, 42, 62, 339, 97, 71, 57, 99, 'POURPRE_COM'),
  473. ('French raspberry', '#C72C48', 78, 17, 28, 349, 64, 48, 78, 78, 'POURPRE_COM'),
  474. ('French sky blue', '#77B5FE', 47, 71, 100, 212, 99, 73, 53, 100, 'POURPRE_COM'),
  475. ('French violet', '#8806CE', 53, 2, 81, 279, 94, 42, 97, 81, 'POURPRE_COM'),
  476. ('Frostbite', '#E936A7', 91, 21, 65, 322, 80, 56, 77, 91, 'CRAYOLA'),
  477. ('Fuchsia', '#FF00FF', 100, 0, 100, 300, 100, 50, 100, 100, 'X11_WEB'),
  478. ('Fuchsia (Crayola)', '#C154C1', 76, 33, 76, 300, 47, 54, 56, 76, 'CRAYOLA'),
  479. ('Fulvous', '#E48400', 89, 52, 0, 35, 100, 45, 100, 89, '99COLORS_NET'),
  480. ('Fuzzy Wuzzy', '#87421F', 53, 26, 12, 20, 63, 33, 77, 53, 'CRAYOLA');
  481. `.trim(),
  482. },
  483. {
  484. id: 12,
  485. type: 'quickstart',
  486. title: 'Slack Clone',
  487. description: 'Build a basic slack clone with Row Level Security.',
  488. sql: `
  489. --
  490. -- For use with https://github.com/briven/briven/tree/master/examples/slack-clone/nextjs-slack-clone
  491. -- Custom types
  492. create type public.app_permission as enum ('channels.delete', 'messages.delete');
  493. create type public.app_role as enum ('admin', 'moderator');
  494. create type public.user_status as enum ('ONLINE', 'OFFLINE');
  495. -- USERS
  496. create table public.users (
  497. id uuid not null primary key, -- UUID from auth.users
  498. username text,
  499. status user_status default 'OFFLINE'::public.user_status
  500. );
  501. comment on table public.users is 'Profile data for each user.';
  502. comment on column public.users.id is 'References the internal Briven Auth user.';
  503. -- CHANNELS
  504. create table public.channels (
  505. id bigint generated by default as identity primary key,
  506. inserted_at timestamp with time zone default timezone('utc'::text, now()) not null,
  507. slug text not null unique,
  508. created_by uuid references public.users not null
  509. );
  510. comment on table public.channels is 'Topics and groups.';
  511. -- MESSAGES
  512. create table public.messages (
  513. id bigint generated by default as identity primary key,
  514. inserted_at timestamp with time zone default timezone('utc'::text, now()) not null,
  515. message text,
  516. user_id uuid references public.users not null,
  517. channel_id bigint references public.channels on delete cascade not null
  518. );
  519. comment on table public.messages is 'Individual messages sent by each user.';
  520. -- USER ROLES
  521. create table public.user_roles (
  522. id bigint generated by default as identity primary key,
  523. user_id uuid references public.users on delete cascade not null,
  524. role app_role not null,
  525. unique (user_id, role)
  526. );
  527. comment on table public.user_roles is 'Application roles for each user.';
  528. -- ROLE PERMISSIONS
  529. create table public.role_permissions (
  530. id bigint generated by default as identity primary key,
  531. role app_role not null,
  532. permission app_permission not null,
  533. unique (role, permission)
  534. );
  535. comment on table public.role_permissions is 'Application permissions for each role.';
  536. -- authorize with role-based access control (RBAC)
  537. create function public.authorize(
  538. requested_permission app_permission,
  539. user_id uuid
  540. )
  541. returns boolean as
  542. $$
  543. declare
  544. bind_permissions int;
  545. begin
  546. select
  547. count(*)
  548. from public.role_permissions
  549. inner join public.user_roles on role_permissions.role = user_roles.role
  550. where
  551. role_permissions.permission = authorize.requested_permission and
  552. user_roles.user_id = authorize.user_id
  553. into bind_permissions;
  554. return bind_permissions > 0;
  555. end;
  556. $$
  557. language plpgsql security definer;
  558. -- Secure the tables
  559. alter table public.users
  560. enable row level security;
  561. alter table public.channels
  562. enable row level security;
  563. alter table public.messages
  564. enable row level security;
  565. alter table public.user_roles
  566. enable row level security;
  567. alter table public.role_permissions
  568. enable row level security;
  569. create policy "Allow logged-in read access" on public.users
  570. for select using (auth.role() = 'authenticated');
  571. create policy "Allow individual insert access" on public.users
  572. for insert with check ((select auth.uid()) = id);
  573. create policy "Allow individual update access" on public.users
  574. for update using ( (select auth.uid()) = id );
  575. create policy "Allow logged-in read access" on public.channels
  576. for select using (auth.role() = 'authenticated');
  577. create policy "Allow individual insert access" on public.channels
  578. for insert with check ((select auth.uid()) = created_by);
  579. create policy "Allow individual delete access" on public.channels
  580. for delete using ((select auth.uid()) = created_by);
  581. create policy "Allow authorized delete access" on public.channels
  582. for delete using (authorize('channels.delete', auth.uid()));
  583. create policy "Allow logged-in read access" on public.messages
  584. for select using (auth.role() = 'authenticated');
  585. create policy "Allow individual insert access" on public.messages
  586. for insert with check ((select auth.uid()) = user_id);
  587. create policy "Allow individual update access" on public.messages
  588. for update using ((select auth.uid()) = user_id);
  589. create policy "Allow individual delete access" on public.messages
  590. for delete using ((select auth.uid()) = user_id);
  591. create policy "Allow authorized delete access" on public.messages
  592. for delete using (authorize('messages.delete', auth.uid()));
  593. create policy "Allow individual read access" on public.user_roles
  594. for select using ((select auth.uid()) = user_id);
  595. -- Send "previous data" on change
  596. alter table public.users
  597. replica identity full;
  598. alter table public.channels
  599. replica identity full;
  600. alter table public.messages
  601. replica identity full;
  602. -- inserts a row into public.users and assigns roles
  603. create function public.handle_new_user()
  604. returns trigger
  605. set search_path = ''
  606. as $$
  607. declare is_admin boolean;
  608. begin
  609. insert into public.users (id, username)
  610. values (new.id, new.email);
  611. select count(*) = 1 from auth.users into is_admin;
  612. if position('+supaadmin@' in new.email) > 0 then
  613. insert into public.user_roles (user_id, role) values (new.id, 'admin');
  614. elsif position('+supamod@' in new.email) > 0 then
  615. insert into public.user_roles (user_id, role) values (new.id, 'moderator');
  616. end if;
  617. return new;
  618. end;
  619. $$ language plpgsql security definer;
  620. -- trigger the function every time a user is created
  621. create trigger on_auth_user_created
  622. after insert on auth.users
  623. for each row execute procedure public.handle_new_user();
  624. /**
  625. * REALTIME SUBSCRIPTIONS
  626. * Only allow realtime listening on public tables.
  627. */
  628. begin;
  629. -- remove the realtime publication
  630. drop publication if exists briven_realtime;
  631. -- re-create the publication but don't enable it for any tables
  632. create publication briven_realtime;
  633. commit;
  634. -- add tables to the publication
  635. alter publication briven_realtime add table public.channels;
  636. alter publication briven_realtime add table public.messages;
  637. alter publication briven_realtime add table public.users;
  638. -- DUMMY DATA
  639. insert into public.users (id, username)
  640. values
  641. ('8d0fd2b3-9ca7-4d9e-a95f-9e13dded323e', 'supabot');
  642. insert into public.channels (slug, created_by)
  643. values
  644. ('public', '8d0fd2b3-9ca7-4d9e-a95f-9e13dded323e'),
  645. ('random', '8d0fd2b3-9ca7-4d9e-a95f-9e13dded323e');
  646. insert into public.messages (message, channel_id, user_id)
  647. values
  648. ('Hello World 👋', 1, '8d0fd2b3-9ca7-4d9e-a95f-9e13dded323e'),
  649. ('Perfection is attained, not when there is nothing more to add, but when there is nothing left to take away.', 2, '8d0fd2b3-9ca7-4d9e-a95f-9e13dded323e');
  650. insert into public.role_permissions (role, permission)
  651. values
  652. ('admin', 'channels.delete'),
  653. ('admin', 'messages.delete'),
  654. ('moderator', 'messages.delete');
  655. `.trim(),
  656. },
  657. {
  658. id: 13,
  659. type: 'quickstart',
  660. title: 'Todo List',
  661. description: 'Build a basic todo list with Row Level Security.',
  662. sql: `
  663. --
  664. -- For use with:
  665. -- https://github.com/briven/briven/tree/master/examples/todo-list/sveltejs-todo-list or
  666. -- https://github.com/briven/examples-archive/tree/main/briven-js-v1/todo-list
  667. --
  668. create table todos (
  669. id bigint generated by default as identity primary key,
  670. user_id uuid references auth.users not null,
  671. task text check (char_length(task) > 3),
  672. is_complete boolean default false,
  673. inserted_at timestamp with time zone default timezone('utc'::text, now()) not null
  674. );
  675. alter table todos enable row level security;
  676. create policy "Individuals can create todos." on todos for
  677. insert with check (auth.uid() = user_id);
  678. create policy "Individuals can view their own todos. " on todos for
  679. select using ((select auth.uid()) = user_id);
  680. create policy "Individuals can update their own todos." on todos for
  681. update using ((select auth.uid()) = user_id);
  682. create policy "Individuals can delete their own todos." on todos for
  683. delete using ((select auth.uid()) = user_id);
  684. `.trim(),
  685. },
  686. {
  687. id: 14,
  688. type: 'quickstart',
  689. title: 'Stripe Subscriptions',
  690. description: 'Starter template for the Next.js Stripe Subscriptions Starter.',
  691. sql: `
  692. /**
  693. * USERS
  694. * Note: This table contains user data. Users should only be able to view and update their own data.
  695. */
  696. create table users (
  697. -- UUID from auth.users
  698. id uuid references auth.users not null primary key,
  699. full_name text,
  700. avatar_url text,
  701. -- The customer's billing address, stored in JSON format.
  702. billing_address jsonb,
  703. -- Stores your customer's payment instruments.
  704. payment_method jsonb
  705. );
  706. alter table users
  707. enable row level security;
  708. create policy "Can view own user data." on users
  709. for select using ((select auth.uid()) = id);
  710. create policy "Can update own user data." on users
  711. for update using ((select auth.uid()) = id);
  712. /**
  713. * This trigger automatically creates a user entry when a new user signs up via Briven Auth.
  714. */
  715. create function public.handle_new_user()
  716. returns trigger
  717. set search_path = ''
  718. as $$
  719. begin
  720. insert into public.users (id, full_name, avatar_url)
  721. values (new.id, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url');
  722. return new;
  723. end;
  724. $$
  725. language plpgsql security definer;
  726. create trigger on_auth_user_created
  727. after insert on auth.users
  728. for each row
  729. execute procedure public.handle_new_user();
  730. /**
  731. * CUSTOMERS
  732. * Note: this is a private table that contains a mapping of user IDs to Stripe customer IDs.
  733. */
  734. create table customers (
  735. -- UUID from auth.users
  736. id uuid references auth.users not null primary key,
  737. -- The user's customer ID in Stripe. User must not be able to update this.
  738. stripe_customer_id text
  739. );
  740. alter table customers enable row level security;
  741. -- No policies as this is a private table that the user must not have access to.
  742. /**
  743. * PRODUCTS
  744. * Note: products are created and managed in Stripe and synced to our DB via Stripe webhooks.
  745. */
  746. create table products (
  747. -- Product ID from Stripe, e.g. prod_1234.
  748. id text primary key,
  749. -- Whether the product is currently available for purchase.
  750. active boolean,
  751. -- The product's name, meant to be displayable to the customer. Whenever this product is sold via a subscription, name will show up on associated invoice line item descriptions.
  752. name text,
  753. -- The product's description, meant to be displayable to the customer. Use this field to optionally store a long form explanation of the product being sold for your own rendering purposes.
  754. description text,
  755. -- A URL of the product image in Stripe, meant to be displayable to the customer.
  756. image text,
  757. -- Set of key-value pairs, used to store additional information about the object in a structured format.
  758. metadata jsonb
  759. );
  760. alter table products
  761. enable row level security;
  762. create policy "Allow public read-only access." on products
  763. for select using (true);
  764. /**
  765. * PRICES
  766. * Note: prices are created and managed in Stripe and synced to our DB via Stripe webhooks.
  767. */
  768. create type pricing_type as enum ('one_time', 'recurring');
  769. create type pricing_plan_interval as enum ('day', 'week', 'month', 'year');
  770. create table prices (
  771. -- Price ID from Stripe, e.g. price_1234.
  772. id text primary key,
  773. -- The ID of the prduct that this price belongs to.
  774. product_id text references products,
  775. -- Whether the price can be used for new purchases.
  776. active boolean,
  777. -- A brief description of the price.
  778. description text,
  779. -- The unit amount as a positive integer in the smallest currency unit (e.g., 100 cents for US$1.00 or 100 for ¥100, a zero-decimal currency).
  780. unit_amount bigint,
  781. -- Three-letter ISO currency code, in lowercase.
  782. currency text check (char_length(currency) = 3),
  783. -- One of \`one_time\` or \`recurring\` depending on whether the price is for a one-time purchase or a recurring (subscription) purchase.
  784. type pricing_type,
  785. -- The frequency at which a subscription is billed. One of \`day\`, \`week\`, \`month\` or \`year\`.
  786. interval pricing_plan_interval,
  787. -- The number of intervals (specified in the \`interval\` attribute) between subscription billings. For example, \`interval=month\` and \`interval_count=3\` bills every 3 months.
  788. interval_count integer,
  789. -- Default number of trial days when subscribing a customer to this price using [\`trial_from_plan=true\`](https://stripe.com/docs/api#create_subscription-trial_from_plan).
  790. trial_period_days integer,
  791. -- Set of key-value pairs, used to store additional information about the object in a structured format.
  792. metadata jsonb
  793. );
  794. alter table prices
  795. enable row level security;
  796. create policy "Allow public read-only access." on prices
  797. for select using (true);
  798. /**
  799. * SUBSCRIPTIONS
  800. * Note: subscriptions are created and managed in Stripe and synced to our DB via Stripe webhooks.
  801. */
  802. create type subscription_status as enum ('trialing', 'active', 'canceled', 'incomplete', 'incomplete_expired', 'past_due', 'unpaid');
  803. create table subscriptions (
  804. -- Subscription ID from Stripe, e.g. sub_1234.
  805. id text primary key,
  806. user_id uuid references auth.users not null,
  807. -- The status of the subscription object, one of subscription_status type above.
  808. status subscription_status,
  809. -- Set of key-value pairs, used to store additional information about the object in a structured format.
  810. metadata jsonb,
  811. -- ID of the price that created this subscription.
  812. price_id text references prices,
  813. -- Quantity multiplied by the unit amount of the price creates the amount of the subscription. Can be used to charge multiple seats.
  814. quantity integer,
  815. -- If true the subscription has been canceled by the user and will be deleted at the end of the billing period.
  816. cancel_at_period_end boolean,
  817. -- Time at which the subscription was created.
  818. created timestamp with time zone default timezone('utc'::text, now()) not null,
  819. -- Start of the current period that the subscription has been invoiced for.
  820. current_period_start timestamp with time zone default timezone('utc'::text, now()) not null,
  821. -- End of the current period that the subscription has been invoiced for. At the end of this period, a new invoice will be created.
  822. current_period_end timestamp with time zone default timezone('utc'::text, now()) not null,
  823. -- If the subscription has ended, the timestamp of the date the subscription ended.
  824. ended_at timestamp with time zone default timezone('utc'::text, now()),
  825. -- A date in the future at which the subscription will automatically get canceled.
  826. cancel_at timestamp with time zone default timezone('utc'::text, now()),
  827. -- If the subscription has been canceled, the date of that cancellation. If the subscription was canceled with \`cancel_at_period_end\`, \`canceled_at\` will still reflect the date of the initial cancellation request, not the end of the subscription period when the subscription is automatically moved to a canceled state.
  828. canceled_at timestamp with time zone default timezone('utc'::text, now()),
  829. -- If the subscription has a trial, the beginning of that trial.
  830. trial_start timestamp with time zone default timezone('utc'::text, now()),
  831. -- If the subscription has a trial, the end of that trial.
  832. trial_end timestamp with time zone default timezone('utc'::text, now())
  833. );
  834. alter table subscriptions
  835. enable row level security;
  836. create policy "Can only view own subs data." on subscriptions
  837. for select using ((select auth.uid()) = user_id);
  838. /**
  839. * REALTIME SUBSCRIPTIONS
  840. * Only allow realtime listening on public tables.
  841. */
  842. drop publication if exists briven_realtime;
  843. create publication briven_realtime
  844. for table products, prices;
  845. `.trim(),
  846. },
  847. {
  848. id: 15,
  849. type: 'quickstart',
  850. title: 'User Management Starter',
  851. description: 'Sets up a public Profiles table which you can access with your API.',
  852. sql: `
  853. -- Create a table for public profiles
  854. create table profiles (
  855. id uuid references auth.users on delete cascade not null primary key,
  856. updated_at timestamp with time zone,
  857. username text unique,
  858. full_name text,
  859. avatar_url text,
  860. website text,
  861. constraint username_length check (char_length(username) >= 3)
  862. );
  863. -- Set up Row Level Security (RLS)
  864. -- See ${DOCS_URL}/guides/auth/row-level-security for more details.
  865. alter table profiles
  866. enable row level security;
  867. create policy "Public profiles are viewable by everyone." on profiles
  868. for select using (true);
  869. create policy "Users can insert their own profile." on profiles
  870. for insert with check ((select auth.uid()) = id);
  871. create policy "Users can update own profile." on profiles
  872. for update using ((select auth.uid()) = id);
  873. -- This trigger automatically creates a profile entry when a new user signs up via Briven Auth.
  874. -- See ${DOCS_URL}/guides/auth/managing-user-data#using-triggers for more details.
  875. create function public.handle_new_user()
  876. returns trigger
  877. set search_path = ''
  878. as $$
  879. begin
  880. insert into public.profiles (id, full_name, avatar_url)
  881. values (new.id, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url');
  882. return new;
  883. end;
  884. $$ language plpgsql security definer;
  885. create trigger on_auth_user_created
  886. after insert on auth.users
  887. for each row execute procedure public.handle_new_user();
  888. -- Set up Storage!
  889. insert into storage.buckets (id, name)
  890. values ('avatars', 'avatars');
  891. -- Set up access controls for storage.
  892. -- See ${DOCS_URL}/guides/storage#policy-examples for more details.
  893. create policy "Avatar images are publicly accessible." on storage.objects
  894. for select using (bucket_id = 'avatars');
  895. create policy "Anyone can upload an avatar." on storage.objects
  896. for insert with check (bucket_id = 'avatars');
  897. `.trim(),
  898. },
  899. {
  900. id: 16,
  901. type: 'quickstart',
  902. title: 'NextAuth Schema Setup',
  903. description: 'Sets up a the Schema and Tables for the NextAuth Briven Adapter.',
  904. sql: `
  905. --
  906. -- Name: next_auth; Type: SCHEMA;
  907. --
  908. CREATE SCHEMA next_auth;
  909. GRANT USAGE ON SCHEMA next_auth TO service_role;
  910. GRANT ALL ON SCHEMA next_auth TO postgres;
  911. --
  912. -- Create users table
  913. --
  914. CREATE TABLE IF NOT EXISTS next_auth.users
  915. (
  916. id uuid NOT NULL DEFAULT gen_random_uuid(),
  917. name text,
  918. email text,
  919. "emailVerified" timestamp with time zone,
  920. image text,
  921. CONSTRAINT users_pkey PRIMARY KEY (id),
  922. CONSTRAINT email_unique UNIQUE (email)
  923. );
  924. GRANT ALL ON TABLE next_auth.users TO postgres;
  925. GRANT ALL ON TABLE next_auth.users TO service_role;
  926. --- uid() function to be used in RLS policies
  927. CREATE FUNCTION next_auth.uid() RETURNS uuid
  928. LANGUAGE sql STABLE
  929. AS $$
  930. select
  931. coalesce(
  932. nullif(current_setting('request.jwt.claim.sub', true), ''),
  933. (nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'sub')
  934. )::uuid
  935. $$;
  936. --
  937. -- Create sessions table
  938. --
  939. CREATE TABLE IF NOT EXISTS next_auth.sessions
  940. (
  941. id uuid NOT NULL DEFAULT gen_random_uuid(),
  942. expires timestamp with time zone NOT NULL,
  943. "sessionToken" text NOT NULL,
  944. "userId" uuid,
  945. CONSTRAINT sessions_pkey PRIMARY KEY (id),
  946. CONSTRAINT sessionToken_unique UNIQUE ("sessionToken"),
  947. CONSTRAINT "sessions_userId_fkey" FOREIGN KEY ("userId")
  948. REFERENCES next_auth.users (id) MATCH SIMPLE
  949. ON UPDATE NO ACTION
  950. ON DELETE CASCADE
  951. );
  952. GRANT ALL ON TABLE next_auth.sessions TO postgres;
  953. GRANT ALL ON TABLE next_auth.sessions TO service_role;
  954. --
  955. -- Create accounts table
  956. --
  957. CREATE TABLE IF NOT EXISTS next_auth.accounts
  958. (
  959. id uuid NOT NULL DEFAULT gen_random_uuid(),
  960. type text NOT NULL,
  961. provider text NOT NULL,
  962. "providerAccountId" text NOT NULL,
  963. refresh_token text,
  964. access_token text,
  965. expires_at bigint,
  966. token_type text,
  967. scope text,
  968. id_token text,
  969. session_state text,
  970. oauth_token_secret text,
  971. oauth_token text,
  972. "userId" uuid,
  973. CONSTRAINT accounts_pkey PRIMARY KEY (id),
  974. CONSTRAINT provider_unique UNIQUE (provider, "providerAccountId"),
  975. CONSTRAINT "accounts_userId_fkey" FOREIGN KEY ("userId")
  976. REFERENCES next_auth.users (id) MATCH SIMPLE
  977. ON UPDATE NO ACTION
  978. ON DELETE CASCADE
  979. );
  980. GRANT ALL ON TABLE next_auth.accounts TO postgres;
  981. GRANT ALL ON TABLE next_auth.accounts TO service_role;
  982. --
  983. -- Create verification_tokens table
  984. --
  985. CREATE TABLE IF NOT EXISTS next_auth.verification_tokens
  986. (
  987. identifier text,
  988. token text,
  989. expires timestamp with time zone NOT NULL,
  990. CONSTRAINT verification_tokens_pkey PRIMARY KEY (token),
  991. CONSTRAINT token_unique UNIQUE (token),
  992. CONSTRAINT token_identifier_unique UNIQUE (token, identifier)
  993. );
  994. GRANT ALL ON TABLE next_auth.verification_tokens TO postgres;
  995. GRANT ALL ON TABLE next_auth.verification_tokens TO service_role;
  996. `.trim(),
  997. },
  998. {
  999. id: 17,
  1000. type: 'template',
  1001. title: 'Most frequently invoked',
  1002. description: 'Most frequently called queries in your database.',
  1003. sql: `-- Most frequently called queries
  1004. -- A limit of 100 has been added below
  1005. select
  1006. auth.rolname,
  1007. statements.query,
  1008. statements.calls,
  1009. -- -- Postgres 13, 14, 15
  1010. statements.total_exec_time + statements.total_plan_time as total_time,
  1011. statements.min_exec_time + statements.min_plan_time as min_time,
  1012. statements.max_exec_time + statements.max_plan_time as max_time,
  1013. statements.mean_exec_time + statements.mean_plan_time as mean_time,
  1014. -- -- Postgres <= 12
  1015. -- total_time,
  1016. -- min_time,
  1017. -- max_time,
  1018. -- mean_time,
  1019. statements.rows / statements.calls as avg_rows
  1020. from pg_stat_statements as statements
  1021. inner join pg_authid as auth on statements.userid = auth.oid
  1022. order by
  1023. statements.calls desc
  1024. limit
  1025. 100;`,
  1026. },
  1027. {
  1028. id: 18,
  1029. type: 'template',
  1030. title: 'Most time consuming',
  1031. description: 'Aggregate time spent on a query type.',
  1032. sql: `-- Most time consuming queries
  1033. -- A limit of 100 has been added below
  1034. select
  1035. auth.rolname,
  1036. statements.query,
  1037. statements.calls,
  1038. statements.total_exec_time + statements.total_plan_time as total_time,
  1039. to_char(((statements.total_exec_time + statements.total_plan_time)/sum(statements.total_exec_time + statements.total_plan_time) over()) * 100, 'FM90D0') || '%' as prop_total_time
  1040. from pg_stat_statements as statements
  1041. inner join pg_authid as auth on statements.userid = auth.oid
  1042. order by
  1043. total_time desc
  1044. limit
  1045. 100;`,
  1046. },
  1047. {
  1048. id: 19,
  1049. type: 'template',
  1050. title: 'Slowest execution time',
  1051. description: 'Slowest queries based on max execution time.',
  1052. sql: `-- Slowest queries by max execution time
  1053. -- A limit of 100 has been added below
  1054. select
  1055. auth.rolname,
  1056. statements.query,
  1057. statements.calls,
  1058. -- -- Postgres 13, 14, 15
  1059. statements.total_exec_time + statements.total_plan_time as total_time,
  1060. statements.min_exec_time + statements.min_plan_time as min_time,
  1061. statements.max_exec_time + statements.max_plan_time as max_time,
  1062. statements.mean_exec_time + statements.mean_plan_time as mean_time,
  1063. -- -- Postgres <= 12
  1064. -- total_time,
  1065. -- min_time,
  1066. -- max_time,
  1067. -- mean_time,
  1068. statements.rows / statements.calls as avg_rows
  1069. from pg_stat_statements as statements
  1070. inner join pg_authid as auth on statements.userid = auth.oid
  1071. order by
  1072. max_time desc
  1073. limit
  1074. 100;`,
  1075. },
  1076. {
  1077. id: 20,
  1078. type: 'template',
  1079. title: 'Hit rate',
  1080. description: 'See your cache and index hit rate.',
  1081. sql: `-- Cache and index hit rate
  1082. select
  1083. 'index hit rate' as name,
  1084. (sum(idx_blks_hit)) / nullif(sum(idx_blks_hit + idx_blks_read),0) as ratio
  1085. from pg_statio_user_indexes
  1086. union all
  1087. select
  1088. 'table hit rate' as name,
  1089. sum(heap_blks_hit) / nullif(sum(heap_blks_hit) + sum(heap_blks_read),0) as ratio
  1090. from pg_statio_user_tables;`,
  1091. },
  1092. {
  1093. id: 21,
  1094. type: 'quickstart',
  1095. title: 'OpenAI Vector Search',
  1096. description: 'Template for the Next.js OpenAI Doc Search Starter.',
  1097. sql: `
  1098. -- Enable pg_vector extension
  1099. create extension if not exists vector with schema public;
  1100. -- Create tables
  1101. create table "public"."nods_page" (
  1102. id bigserial primary key,
  1103. parent_page_id bigint references public.nods_page,
  1104. path text not null unique,
  1105. checksum text,
  1106. meta jsonb,
  1107. type text,
  1108. source text
  1109. );
  1110. alter table "public"."nods_page" enable row level security;
  1111. create table "public"."nods_page_section" (
  1112. id bigserial primary key,
  1113. page_id bigint not null references public.nods_page on delete cascade,
  1114. content text,
  1115. token_count int,
  1116. embedding vector(1536),
  1117. slug text,
  1118. heading text
  1119. );
  1120. alter table "public"."nods_page_section" enable row level security;
  1121. -- Create embedding similarity search functions
  1122. create or replace function match_page_sections(embedding vector(1536), match_threshold float, match_count int, min_content_length int)
  1123. returns table (id bigint, page_id bigint, slug text, heading text, content text, similarity float)
  1124. language plpgsql
  1125. as $$
  1126. #variable_conflict use_variable
  1127. begin
  1128. return query
  1129. select
  1130. nods_page_section.id,
  1131. nods_page_section.page_id,
  1132. nods_page_section.slug,
  1133. nods_page_section.heading,
  1134. nods_page_section.content,
  1135. (nods_page_section.embedding <#> embedding) * -1 as similarity
  1136. from nods_page_section
  1137. -- We only care about sections that have a useful amount of content
  1138. where length(nods_page_section.content) >= min_content_length
  1139. -- The dot product is negative because of a Postgres limitation, so we negate it
  1140. and (nods_page_section.embedding <#> embedding) * -1 > match_threshold
  1141. -- OpenAI embeddings are normalized to length 1, so
  1142. -- cosine similarity and dot product will produce the same results.
  1143. -- Using dot product which can be computed slightly faster.
  1144. --
  1145. -- For the different syntaxes, see https://github.com/pgvector/pgvector
  1146. order by nods_page_section.embedding <#> embedding
  1147. limit match_count;
  1148. end;
  1149. $$;
  1150. create or replace function get_page_parents(page_id bigint)
  1151. returns table (id bigint, parent_page_id bigint, path text, meta jsonb)
  1152. language sql
  1153. as $$
  1154. with recursive chain as (
  1155. select *
  1156. from nods_page
  1157. where id = page_id
  1158. union all
  1159. select child.*
  1160. from nods_page as child
  1161. join chain on chain.parent_page_id = child.id
  1162. )
  1163. select id, parent_page_id, path, meta
  1164. from chain;
  1165. $$;
  1166. `.trim(),
  1167. },
  1168. {
  1169. id: 22,
  1170. type: 'template',
  1171. title: 'Replication status report',
  1172. description: 'See the status of your replication slots and replication lag.',
  1173. sql: `-- Replication status report
  1174. SELECT
  1175. s.slot_name,
  1176. s.active,
  1177. COALESCE(r.state, 'N/A') as state,
  1178. COALESCE(r.client_addr, null) as replication_client_address,
  1179. GREATEST(0, ROUND((redo_lsn-restart_lsn)/1024/1024/1024, 2)) as replication_lag_gb
  1180. FROM pg_control_checkpoint(), pg_replication_slots s
  1181. LEFT JOIN pg_stat_replication r ON (r.pid = s.active_pid);
  1182. `,
  1183. },
  1184. {
  1185. id: 23,
  1186. type: 'quickstart',
  1187. title: 'LangChain',
  1188. description: 'LangChain is a popular framework for working with AI, Vectors, and embeddings.',
  1189. sql: `
  1190. -- Enable the pgvector extension to work with embedding vectors
  1191. create extension vector;
  1192. -- Create a table to store your documents
  1193. create table documents (
  1194. id bigserial primary key,
  1195. content text, -- corresponds to Document.pageContent
  1196. metadata jsonb, -- corresponds to Document.metadata
  1197. embedding vector(1536) -- 1536 works for OpenAI embeddings, change if needed
  1198. );
  1199. -- Create a function to search for documents
  1200. create function match_documents (
  1201. query_embedding vector(1536),
  1202. match_count int default null,
  1203. filter jsonb DEFAULT '{}'
  1204. ) returns table (
  1205. id bigint,
  1206. content text,
  1207. metadata jsonb,
  1208. similarity float
  1209. )
  1210. language plpgsql
  1211. as $$
  1212. #variable_conflict use_column
  1213. begin
  1214. return query
  1215. select
  1216. id,
  1217. content,
  1218. metadata,
  1219. 1 - (documents.embedding <=> query_embedding) as similarity
  1220. from documents
  1221. where metadata @> filter
  1222. order by documents.embedding <=> query_embedding
  1223. limit match_count;
  1224. end;
  1225. $$;
  1226. `.trim(),
  1227. },
  1228. {
  1229. id: 24,
  1230. type: 'template',
  1231. title: 'Install dbdev',
  1232. description:
  1233. 'dbdev is a client for installing Trusted Language Extensions (TLE) into your database.',
  1234. sql: `
  1235. /*---------------------
  1236. ---- install dbdev ----
  1237. -----------------------
  1238. Requires:
  1239. - pg_tle: https://github.com/aws/pg_tle
  1240. - pgsql-http: https://github.com/pramsey/pgsql-http
  1241. Warning:
  1242. Restoring a logical backup of a database with a TLE installed can fail.
  1243. For this reason, dbdev should only be used with databases with physical backups enabled.
  1244. */
  1245. create extension if not exists http with schema extensions;
  1246. create extension if not exists pg_tle;
  1247. select pgtle.uninstall_extension_if_exists('briven-dbdev');
  1248. drop extension if exists "briven-dbdev";
  1249. select
  1250. pgtle.install_extension(
  1251. 'briven-dbdev',
  1252. resp.contents ->> 'version',
  1253. 'PostgreSQL package manager',
  1254. resp.contents ->> 'sql'
  1255. )
  1256. from http(
  1257. (
  1258. 'GET',
  1259. 'https://api.database.dev/rest/v1/'
  1260. || 'package_versions?select=sql,version'
  1261. || '&package_name=eq.briven-dbdev'
  1262. || '&order=version.desc'
  1263. || '&limit=1',
  1264. array[
  1265. ('apiKey', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InhtdXB0cHBsZnZpaWZyYndtbXR2Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2ODAxMDczNzIsImV4cCI6MTk5NTY4MzM3Mn0.z2CN0mvO2No8wSi46Gw59DFGCTJrzM0AQKsu_5k134s')::http_header
  1266. ],
  1267. null,
  1268. null
  1269. )
  1270. ) x,
  1271. lateral (
  1272. select
  1273. ((row_to_json(x) -> 'content') #>> '{}')::json -> 0
  1274. ) resp(contents);
  1275. create extension "briven-dbdev";
  1276. select dbdev.install('briven-dbdev');
  1277. drop extension if exists "briven-dbdev";
  1278. create extension "briven-dbdev";
  1279. `.trim(),
  1280. },
  1281. {
  1282. id: 25,
  1283. type: 'template',
  1284. title: 'Large objects',
  1285. description: 'List large objects (tables/indexes) in your database.',
  1286. sql: `SELECT
  1287. SCHEMA_NAME,
  1288. relname,
  1289. table_size
  1290. FROM
  1291. (SELECT
  1292. pg_catalog.pg_namespace.nspname AS SCHEMA_NAME,
  1293. relname,
  1294. pg_relation_size(pg_catalog.pg_class.oid) AS table_size
  1295. FROM pg_catalog.pg_class
  1296. JOIN pg_catalog.pg_namespace ON relnamespace = pg_catalog.pg_namespace.oid
  1297. ) t
  1298. WHERE SCHEMA_NAME NOT LIKE 'pg_%'
  1299. ORDER BY table_size DESC
  1300. LIMIT 25`.trim(),
  1301. },
  1302. {
  1303. id: 26,
  1304. type: 'template',
  1305. title: 'Limit MFA verification attempts to one in 2 seconds',
  1306. description:
  1307. 'Create an Auth hook that limits the number of failed MFA verification attempts to one in 2 seconds.',
  1308. sql: `
  1309. create function public.hook_mfa_verification_attempt(event jsonb)
  1310. returns jsonb
  1311. language plpgsql
  1312. as $$
  1313. declare
  1314. last_failed_at timestamp;
  1315. begin
  1316. if event->'valid' is true then
  1317. -- code is valid, accept it
  1318. return jsonb_build_object('decision', 'continue');
  1319. end if;
  1320. select last_failed_at into last_failed_at
  1321. from public.mfa_failed_verification_attempts
  1322. where
  1323. user_id = (event->'user_id')::uuid
  1324. and
  1325. factor_id = event->'factor_id';
  1326. if last_failed_at is not null and now() - last_failed_at < interval '2 seconds' then
  1327. -- last attempt was done too quickly
  1328. return jsonb_build_object(
  1329. 'error', jsonb_build_object(
  1330. 'http_code', 429,
  1331. 'message', 'Please wait a moment before trying again.'
  1332. )
  1333. );
  1334. end if;
  1335. -- record this failed attempt
  1336. insert into public.mfa_failed_verification_attempts
  1337. (
  1338. user_id,
  1339. factor_id,
  1340. last_refreshed_at
  1341. )
  1342. values
  1343. (
  1344. event->'user_id',
  1345. event->'factor_id',
  1346. now()
  1347. )
  1348. on conflict do update
  1349. set last_refreshed_at = now();
  1350. -- finally let Briven Auth do the default behavior for a failed attempt
  1351. return jsonb_build_object('decision', 'continue');
  1352. end;
  1353. $$;
  1354. -- Assign appropriate permissions and revoke access
  1355. grant execute
  1356. on function public.hook_mfa_verification_attempt
  1357. to briven_auth_admin;
  1358. grant all
  1359. on table public.mfa_failed_verification_attempts
  1360. to briven_auth_admin;
  1361. revoke execute
  1362. on function public.hook_mfa_verification_attempt
  1363. from authenticated, anon, public;
  1364. revoke all
  1365. on table public.mfa_failed_verification_attempts
  1366. from authenticated, anon, public;
  1367. grant usage on schema public to briven_auth_admin;`.trim(),
  1368. },
  1369. {
  1370. id: 27,
  1371. type: 'template',
  1372. title: 'Add Auth Hook (Password Verification Attempt)',
  1373. description:
  1374. 'Create an Auth Hook that limits number of failed password verification attempts to one in 10 seconds',
  1375. sql: `
  1376. create function public.hook_password_verification_attempt(event jsonb)
  1377. returns jsonb
  1378. language plpgsql
  1379. as $$
  1380. declare
  1381. last_failed_at timestamp;
  1382. begin
  1383. if event->'valid' is true then
  1384. -- password is valid, accept it
  1385. return jsonb_build_object('decision', 'continue');
  1386. end if;
  1387. select last_failed_at into last_failed_at
  1388. from public.password_failed_verification_attempts
  1389. where
  1390. user_id = (event->'user_id')::uuid;
  1391. if last_failed_at is not null and now() - last_failed_at < interval '10 seconds' then
  1392. -- last attempt was done too quickly
  1393. return jsonb_build_object(
  1394. 'error', jsonb_build_object(
  1395. 'http_code', 429,
  1396. 'message', 'Please wait a moment before trying again.'
  1397. )
  1398. );
  1399. end if;
  1400. -- record this failed attempt
  1401. insert into public.password_failed_verification_attempts
  1402. (
  1403. user_id,
  1404. last_failed_at
  1405. )
  1406. values
  1407. (
  1408. event->'user_id',
  1409. now()
  1410. )
  1411. on conflict do update
  1412. set last_failed_at = now();
  1413. -- finally let Briven Auth do the default behavior for a failed attempt
  1414. return jsonb_build_object('decision', 'continue');
  1415. end;
  1416. $$;
  1417. -- Assign appropriate permissions
  1418. grant execute
  1419. on function public.hook_password_verification_attempt
  1420. to briven_auth_admin;
  1421. grant all
  1422. on table public.password_failed_verification_attempts
  1423. to briven_auth_admin;
  1424. revoke execute
  1425. on function public.hook_password_verification_attempt
  1426. from authenticated, anon, public;
  1427. revoke all
  1428. on table public.password_failed_verification_attempts
  1429. from authenticated, anon, public;
  1430. grant usage on schema public to briven_auth_admin;`.trim(),
  1431. },
  1432. {
  1433. id: 28,
  1434. type: 'template',
  1435. title: 'Add Auth Hook (Custom Access Token)',
  1436. description: 'Create an Auth Hook to add custom claims to your Auth Token',
  1437. sql: `
  1438. -- Assumes that there is an is_admin flag on the profiles table.
  1439. create or replace function public.custom_access_token_hook(event jsonb)
  1440. returns jsonb
  1441. language plpgsql
  1442. as $$
  1443. declare
  1444. claims jsonb;
  1445. is_admin boolean;
  1446. begin
  1447. -- Check if the user is marked as admin in the profiles table
  1448. select is_admin into is_admin from profiles where user_id = (event->>'user_id')::uuid;
  1449. -- Proceed only if the user is an admin
  1450. if is_admin then
  1451. claims := event->'claims';
  1452. -- Check if 'user_metadata' exists in claims
  1453. if jsonb_typeof(claims->'user_metadata') is null then
  1454. -- If 'user_metadata' does not exist, create an empty object
  1455. claims := jsonb_set(claims, '{user_metadata}', '{}');
  1456. end if;
  1457. -- Set a claim of 'admin'
  1458. claims := jsonb_set(claims, '{user_metadata, admin}', 'true');
  1459. -- Update the 'claims' object in the original event
  1460. event := jsonb_set(event, '{claims}', claims);
  1461. end if;
  1462. -- Return the modified or original event
  1463. return event;
  1464. end;
  1465. $$;
  1466. grant execute
  1467. on function public.custom_access_token_hook
  1468. to briven_auth_admin;
  1469. revoke execute
  1470. on function public.custom_access_token_hook
  1471. from authenticated, anon, public;
  1472. grant usage on schema public to briven_auth_admin;`.trim(),
  1473. },
  1474. {
  1475. id: 29,
  1476. type: 'template',
  1477. title: 'Add Auth Hook (General)',
  1478. description: 'Create an Auth Hook',
  1479. sql: `
  1480. create or replace function public.custom_access_token_hook(event jsonb)
  1481. returns jsonb
  1482. language plpgsql
  1483. as $$
  1484. declare
  1485. -- Insert variables here
  1486. begin
  1487. -- Insert logic here
  1488. return event;
  1489. end;
  1490. $$;
  1491. -- Permissions for the hook
  1492. grant execute on function public.custom_access_token_hook to briven_auth_admin;
  1493. revoke execute on function public.custom_access_token_hook from authenticated, anon, public;
  1494. `,
  1495. },
  1496. ]