@evertonferreira96/agents 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/.claude/agents/api.md +45 -0
  2. package/.claude/agents/app.md +41 -0
  3. package/.claude/agents/architect.md +49 -0
  4. package/.claude/agents/infra.md +27 -0
  5. package/.claude/agents/product.md +58 -0
  6. package/.claude/agents/quick.md +33 -0
  7. package/.claude/agents/security.md +39 -0
  8. package/.claude/agents/ui.md +54 -0
  9. package/.claude/agents/verifier.md +56 -0
  10. package/.claude/agents/web.md +41 -0
  11. package/.claude/hooks/config-update-check.mjs +14 -0
  12. package/.claude/hooks/context-budget.mjs +51 -0
  13. package/.claude/hooks/graphify-update.sh +16 -0
  14. package/.claude/hooks/guard-bash.sh +64 -0
  15. package/.claude/hooks/orchestrator-guard.sh +49 -0
  16. package/.claude/hooks/post-compact.sh +26 -0
  17. package/.claude/hooks/readonly-guard.sh +54 -0
  18. package/.claude/hooks/stop-verify.sh +52 -0
  19. package/.claude/rules/api.md +21 -0
  20. package/.claude/rules/db.md +9 -0
  21. package/.claude/rules/delivery-diagram.md +16 -0
  22. package/.claude/rules/git-workflow.md +34 -0
  23. package/.claude/rules/graphify.md +3 -0
  24. package/.claude/rules/mobile.md +22 -0
  25. package/.claude/rules/tickets.md +9 -0
  26. package/.claude/rules/ui.md +14 -0
  27. package/.claude/rules/web.md +27 -0
  28. package/.claude/settings.json +114 -0
  29. package/.claude/skills/animate/RECIPES.md +324 -0
  30. package/.claude/skills/animate/SKILL.md +208 -0
  31. package/.claude/skills/animate/agents/openai.yaml +5 -0
  32. package/.claude/skills/animate-expo/RECIPES.md +385 -0
  33. package/.claude/skills/animate-expo/SKILL.md +264 -0
  34. package/.claude/skills/animate-expo/agents/openai.yaml +5 -0
  35. package/.claude/skills/animation-performance/SKILL.md +223 -0
  36. package/.claude/skills/animation-performance/agents/openai.yaml +5 -0
  37. package/.claude/skills/apple-design/SKILL.md +291 -0
  38. package/.claude/skills/apple-design/agents/openai.yaml +5 -0
  39. package/.claude/skills/arch-api/SKILL.md +291 -0
  40. package/.claude/skills/arch-api/agents/openai.yaml +3 -0
  41. package/.claude/skills/arch-api/references/common.md +174 -0
  42. package/.claude/skills/arch-api/references/contract.md +289 -0
  43. package/.claude/skills/arch-api/references/domain.md +301 -0
  44. package/.claude/skills/arch-api/references/endpoints.md +184 -0
  45. package/.claude/skills/arch-api/references/review.md +228 -0
  46. package/.claude/skills/arch-api/references/security.md +151 -0
  47. package/.claude/skills/arch-app/SKILL.md +278 -0
  48. package/.claude/skills/arch-app/agents/openai.yaml +3 -0
  49. package/.claude/skills/arch-app/references/navigation-session.md +257 -0
  50. package/.claude/skills/arch-app/references/review.md +155 -0
  51. package/.claude/skills/arch-app/references/screens.md +214 -0
  52. package/.claude/skills/arch-app/references/services.md +301 -0
  53. package/.claude/skills/arch-app/references/ui-mobile.md +124 -0
  54. package/.claude/skills/arch-db/SKILL.md +181 -0
  55. package/.claude/skills/arch-db/agents/openai.yaml +3 -0
  56. package/.claude/skills/arch-db/references/indexes-queries.md +251 -0
  57. package/.claude/skills/arch-db/references/migrations.md +191 -0
  58. package/.claude/skills/arch-db/references/modeling.md +214 -0
  59. package/.claude/skills/arch-db/references/mysql.md +262 -0
  60. package/.claude/skills/arch-db/references/pooling-ops.md +112 -0
  61. package/.claude/skills/arch-db/references/review.md +143 -0
  62. package/.claude/skills/arch-db/references/transactions-locks.md +141 -0
  63. package/.claude/skills/arch-web/SKILL.md +307 -0
  64. package/.claude/skills/arch-web/agents/openai.yaml +3 -0
  65. package/.claude/skills/arch-web/references/auth-session-env.md +165 -0
  66. package/.claude/skills/arch-web/references/blocks.md +198 -0
  67. package/.claude/skills/arch-web/references/cache.md +124 -0
  68. package/.claude/skills/arch-web/references/review.md +142 -0
  69. package/.claude/skills/arch-web/references/services.md +297 -0
  70. package/.claude/skills/arch-web/references/tests.md +159 -0
  71. package/.claude/skills/arch-web/references/ui-forms.md +143 -0
  72. package/.claude/skills/break-ui/CATALOG.md +135 -0
  73. package/.claude/skills/break-ui/SKILL.md +176 -0
  74. package/.claude/skills/break-ui/agents/openai.yaml +5 -0
  75. package/.claude/skills/brief/SKILL.md +91 -0
  76. package/.claude/skills/brief/agents/openai.yaml +3 -0
  77. package/.claude/skills/diagnosing-bugs/SKILL.md +138 -0
  78. package/.claude/skills/diagnosing-bugs/agents/openai.yaml +3 -0
  79. package/.claude/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
  80. package/.claude/skills/emil-design-eng/SKILL.md +675 -0
  81. package/.claude/skills/emil-design-eng/agents/openai.yaml +5 -0
  82. package/.claude/skills/find-animation-opportunities/SKILL.md +141 -0
  83. package/.claude/skills/find-animation-opportunities/agents/openai.yaml +5 -0
  84. package/.claude/skills/graphify/.graphify_version +1 -0
  85. package/.claude/skills/graphify/SKILL.md +742 -0
  86. package/.claude/skills/graphify/agents/openai.yaml +3 -0
  87. package/.claude/skills/graphify/references/add-watch.md +56 -0
  88. package/.claude/skills/graphify/references/exports.md +91 -0
  89. package/.claude/skills/graphify/references/extraction-spec.md +70 -0
  90. package/.claude/skills/graphify/references/github-and-merge.md +46 -0
  91. package/.claude/skills/graphify/references/hooks.md +33 -0
  92. package/.claude/skills/graphify/references/query.md +317 -0
  93. package/.claude/skills/graphify/references/transcribe.md +52 -0
  94. package/.claude/skills/graphify/references/update.md +221 -0
  95. package/.claude/skills/grill-me/SKILL.md +7 -0
  96. package/.claude/skills/grill-me/agents/openai.yaml +5 -0
  97. package/.claude/skills/grill-with-docs/SKILL.md +64 -0
  98. package/.claude/skills/grill-with-docs/agents/openai.yaml +5 -0
  99. package/.claude/skills/grilling/SKILL.md +30 -0
  100. package/.claude/skills/grilling/agents/openai.yaml +3 -0
  101. package/.claude/skills/handoff/SKILL.md +28 -0
  102. package/.claude/skills/handoff/agents/openai.yaml +5 -0
  103. package/.claude/skills/impeccable/SKILL.md +89 -0
  104. package/.claude/skills/impeccable/agents/openai.yaml +5 -0
  105. package/.claude/skills/impeccable/reference/adapt.md +318 -0
  106. package/.claude/skills/impeccable/reference/adapt.native.md +58 -0
  107. package/.claude/skills/impeccable/reference/android.md +46 -0
  108. package/.claude/skills/impeccable/reference/animate.md +89 -0
  109. package/.claude/skills/impeccable/reference/audit.md +137 -0
  110. package/.claude/skills/impeccable/reference/audit.native.md +139 -0
  111. package/.claude/skills/impeccable/reference/bolder.md +33 -0
  112. package/.claude/skills/impeccable/reference/clarify.md +94 -0
  113. package/.claude/skills/impeccable/reference/colorize.md +86 -0
  114. package/.claude/skills/impeccable/reference/component-review.md +63 -0
  115. package/.claude/skills/impeccable/reference/craft-floor.md +44 -0
  116. package/.claude/skills/impeccable/reference/craft.md +5 -0
  117. package/.claude/skills/impeccable/reference/critique.md +809 -0
  118. package/.claude/skills/impeccable/reference/degraded/asset-producer.md +42 -0
  119. package/.claude/skills/impeccable/reference/degraded/documenter.md +24 -0
  120. package/.claude/skills/impeccable/reference/degraded/finish-reviewer.md +38 -0
  121. package/.claude/skills/impeccable/reference/degraded/manual-edit-applier.md +92 -0
  122. package/.claude/skills/impeccable/reference/delight.md +70 -0
  123. package/.claude/skills/impeccable/reference/distill.md +111 -0
  124. package/.claude/skills/impeccable/reference/doctor.md +54 -0
  125. package/.claude/skills/impeccable/reference/document.md +416 -0
  126. package/.claude/skills/impeccable/reference/extract.md +69 -0
  127. package/.claude/skills/impeccable/reference/generate.md +101 -0
  128. package/.claude/skills/impeccable/reference/harden.md +345 -0
  129. package/.claude/skills/impeccable/reference/hooks.md +113 -0
  130. package/.claude/skills/impeccable/reference/init.md +131 -0
  131. package/.claude/skills/impeccable/reference/ios.md +51 -0
  132. package/.claude/skills/impeccable/reference/layout.md +84 -0
  133. package/.claude/skills/impeccable/reference/live-setup.md +104 -0
  134. package/.claude/skills/impeccable/reference/live.md +325 -0
  135. package/.claude/skills/impeccable/reference/mode-operate.md +21 -0
  136. package/.claude/skills/impeccable/reference/mode-persuade.md +19 -0
  137. package/.claude/skills/impeccable/reference/mode-read.md +21 -0
  138. package/.claude/skills/impeccable/reference/new-work.md +154 -0
  139. package/.claude/skills/impeccable/reference/onboard.md +234 -0
  140. package/.claude/skills/impeccable/reference/operate.md +61 -0
  141. package/.claude/skills/impeccable/reference/optimize.md +258 -0
  142. package/.claude/skills/impeccable/reference/overdrive.md +127 -0
  143. package/.claude/skills/impeccable/reference/polish.md +105 -0
  144. package/.claude/skills/impeccable/reference/quieter.md +99 -0
  145. package/.claude/skills/impeccable/reference/region-map.md +26 -0
  146. package/.claude/skills/impeccable/reference/routing.md +24 -0
  147. package/.claude/skills/impeccable/reference/shape.md +59 -0
  148. package/.claude/skills/impeccable/reference/typeset.md +80 -0
  149. package/.claude/skills/impeccable/reference/visualize.md +47 -0
  150. package/.claude/skills/impeccable/scripts/VERSION +1 -0
  151. package/.claude/skills/impeccable/scripts/command-metadata.json +98 -0
  152. package/.claude/skills/impeccable/scripts/data/font-index-failures.json +121 -0
  153. package/.claude/skills/impeccable/scripts/data/font-index.json +1 -0
  154. package/.claude/skills/impeccable/scripts/impeccable +206 -0
  155. package/.claude/skills/impeccable/scripts/impeccable.cmd +214 -0
  156. package/.claude/skills/impeccable/scripts/live-browser-dom.js +281 -0
  157. package/.claude/skills/impeccable/scripts/live-browser-ignores.js +242 -0
  158. package/.claude/skills/impeccable/scripts/live-browser-session.js +148 -0
  159. package/.claude/skills/impeccable/scripts/live-browser.js +13532 -0
  160. package/.claude/skills/impeccable/scripts/modern-screenshot.umd.js +14 -0
  161. package/.claude/skills/improve-animations/AUDIT.md +115 -0
  162. package/.claude/skills/improve-animations/PLAN-TEMPLATE.md +73 -0
  163. package/.claude/skills/improve-animations/SKILL.md +110 -0
  164. package/.claude/skills/improve-animations/agents/openai.yaml +5 -0
  165. package/.claude/skills/mobile-native/SKILL.md +311 -0
  166. package/.claude/skills/mobile-native/agents/openai.yaml +3 -0
  167. package/.claude/skills/orchestrate/SKILL.md +181 -0
  168. package/.claude/skills/orchestrate/agents/openai.yaml +3 -0
  169. package/.claude/skills/pick-ui-library/SKILL.md +85 -0
  170. package/.claude/skills/pick-ui-library/agents/openai.yaml +5 -0
  171. package/.claude/skills/ponytail/SKILL.md +52 -0
  172. package/.claude/skills/ponytail/agents/openai.yaml +3 -0
  173. package/.claude/skills/ponytail-audit/SKILL.md +103 -0
  174. package/.claude/skills/ponytail-audit/agents/openai.yaml +3 -0
  175. package/.claude/skills/ponytail-debt/SKILL.md +44 -0
  176. package/.claude/skills/ponytail-debt/agents/openai.yaml +3 -0
  177. package/.claude/skills/ponytail-review/SKILL.md +101 -0
  178. package/.claude/skills/ponytail-review/agents/openai.yaml +3 -0
  179. package/.claude/skills/postgres-best-practices/SKILL.md +42 -0
  180. package/.claude/skills/postgres-best-practices/agents/openai.yaml +3 -0
  181. package/.claude/skills/postgres-best-practices/references/backup-restore.md +372 -0
  182. package/.claude/skills/postgres-best-practices/references/bulk-loading.md +315 -0
  183. package/.claude/skills/postgres-best-practices/references/connection-pooling.md +310 -0
  184. package/.claude/skills/postgres-best-practices/references/hot-standby.md +221 -0
  185. package/.claude/skills/postgres-best-practices/references/indexing.md +318 -0
  186. package/.claude/skills/postgres-best-practices/references/logical-replication.md +610 -0
  187. package/.claude/skills/postgres-best-practices/references/major-version-upgrades.md +334 -0
  188. package/.claude/skills/postgres-best-practices/references/performance-diagnostics.md +553 -0
  189. package/.claude/skills/postgres-best-practices/references/query-optimization.md +294 -0
  190. package/.claude/skills/postgres-best-practices/references/query-patterns.md +566 -0
  191. package/.claude/skills/postgres-best-practices/references/schema-design.md +362 -0
  192. package/.claude/skills/postgres-best-practices/references/security-roles.md +489 -0
  193. package/.claude/skills/postgres-best-practices/references/transaction-isolation.md +344 -0
  194. package/.claude/skills/project-docs/SKILL.md +330 -0
  195. package/.claude/skills/project-docs/agents/openai.yaml +3 -0
  196. package/.claude/skills/prototype/PICKER.md +197 -0
  197. package/.claude/skills/prototype/SKILL.md +98 -0
  198. package/.claude/skills/prototype/agents/openai.yaml +5 -0
  199. package/.claude/skills/retro/SKILL.md +43 -0
  200. package/.claude/skills/retro/agents/openai.yaml +5 -0
  201. package/.claude/skills/review/SKILL.md +74 -0
  202. package/.claude/skills/review/agents/openai.yaml +3 -0
  203. package/.claude/skills/review/references/smells.md +23 -0
  204. package/.claude/skills/review-animations/SKILL.md +120 -0
  205. package/.claude/skills/review-animations/STANDARDS.md +187 -0
  206. package/.claude/skills/review-animations/agents/openai.yaml +5 -0
  207. package/.claude/skills/tdd/SKILL.md +38 -0
  208. package/.claude/skills/tdd/agents/openai.yaml +3 -0
  209. package/.claude/skills/tdd/mocking.md +59 -0
  210. package/.claude/skills/tdd/tests.md +77 -0
  211. package/.claude/skills/triage/SKILL.md +58 -0
  212. package/.claude/skills/triage/agents/openai.yaml +3 -0
  213. package/.claude/skills/ui-ux-pro-max/SKILL.md +378 -0
  214. package/.claude/skills/ui-ux-pro-max/agents/openai.yaml +5 -0
  215. package/.claude/skills/ui-ux-pro-max/data/charts.csv +26 -0
  216. package/.claude/skills/ui-ux-pro-max/data/colors.csv +97 -0
  217. package/.claude/skills/ui-ux-pro-max/data/icons.csv +101 -0
  218. package/.claude/skills/ui-ux-pro-max/data/landing.csv +31 -0
  219. package/.claude/skills/ui-ux-pro-max/data/products.csv +97 -0
  220. package/.claude/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  221. package/.claude/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  222. package/.claude/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  223. package/.claude/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  224. package/.claude/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  225. package/.claude/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  226. package/.claude/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  227. package/.claude/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  228. package/.claude/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  229. package/.claude/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  230. package/.claude/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  231. package/.claude/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  232. package/.claude/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  233. package/.claude/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  234. package/.claude/skills/ui-ux-pro-max/data/styles.csv +68 -0
  235. package/.claude/skills/ui-ux-pro-max/data/typography.csv +58 -0
  236. package/.claude/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  237. package/.claude/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  238. package/.claude/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
  239. package/.claude/skills/ui-ux-pro-max/scripts/core.py +253 -0
  240. package/.claude/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
  241. package/.claude/skills/ui-ux-pro-max/scripts/search.py +114 -0
  242. package/.claude/skills/writing-for-agents/SKILL-MECHANICS.md +22 -0
  243. package/.claude/skills/writing-for-agents/SKILL.md +81 -0
  244. package/.claude/skills/writing-for-agents/agents/openai.yaml +3 -0
  245. package/.worktreeinclude +3 -0
  246. package/AGENTS.md +44 -0
  247. package/README.md +14 -2
  248. package/VERSION +1 -0
  249. package/bin/agents.mjs +45 -0
  250. package/docs/adr/README.md +31 -0
  251. package/docs/brief-template.md +3 -0
  252. package/docs/plans/README.md +73 -0
  253. package/package.json +46 -4
  254. package/scripts/bootstrap.mjs +188 -0
  255. package/scripts/check-catalog.mjs +43 -0
  256. package/scripts/skills-update.mjs +51 -0
  257. package/skills-lock.json +269 -0
  258. package/templates/CLAUDE.project.md +41 -0
@@ -0,0 +1,566 @@
1
+ # SQL Query Patterns Reference
2
+
3
+ ## Contents
4
+ - Common Table Expressions (CTEs)
5
+ - Window functions
6
+ - Lateral joins
7
+ - Recursive queries
8
+ - UPSERT (INSERT ON CONFLICT)
9
+ - Bulk operations
10
+ - JSONB queries
11
+ - Date/time patterns
12
+ - Anti-patterns to avoid
13
+
14
+ ## Common Table Expressions (CTEs)
15
+
16
+ ### Readability CTEs
17
+
18
+ ```sql
19
+ WITH active_customers AS (
20
+ SELECT id, name, email
21
+ FROM customers
22
+ WHERE status = 'active'
23
+ ),
24
+ recent_orders AS (
25
+ SELECT customer_id, count(*) AS order_count, max(created_at) AS last_order
26
+ FROM orders
27
+ WHERE created_at > now() - interval '90 days'
28
+ GROUP BY customer_id
29
+ )
30
+ SELECT ac.name, ac.email, ro.order_count, ro.last_order
31
+ FROM active_customers ac
32
+ JOIN recent_orders ro ON ro.customer_id = ac.id
33
+ ORDER BY ro.order_count DESC;
34
+ ```
35
+
36
+ ### CTE Materialization
37
+
38
+ By default the optimizer may inline CTEs. Force materialization when:
39
+ - The CTE is referenced multiple times
40
+ - You want to create an optimization fence
41
+
42
+ ```sql
43
+ WITH expensive_calc AS MATERIALIZED (
44
+ SELECT ... -- complex aggregation
45
+ )
46
+ SELECT * FROM expensive_calc WHERE ...
47
+ UNION ALL
48
+ SELECT * FROM expensive_calc WHERE ...;
49
+ ```
50
+
51
+ Force inlining (default for single-use):
52
+ ```sql
53
+ WITH simple_filter AS NOT MATERIALIZED (
54
+ SELECT * FROM large_table WHERE status = 'active'
55
+ )
56
+ SELECT * FROM simple_filter WHERE created_at > '2024-01-01';
57
+ ```
58
+
59
+ ## Window Functions
60
+
61
+ ### Ranking
62
+
63
+ ```sql
64
+ -- Row number (no ties)
65
+ SELECT *, row_number() OVER (PARTITION BY department ORDER BY salary DESC) AS rn
66
+ FROM employees;
67
+
68
+ -- Rank (ties get same rank, gaps after)
69
+ SELECT *, rank() OVER (ORDER BY score DESC) AS rank
70
+ FROM leaderboard;
71
+
72
+ -- Dense rank (no gaps)
73
+ SELECT *, dense_rank() OVER (ORDER BY score DESC) AS dense_rank
74
+ FROM leaderboard;
75
+ ```
76
+
77
+ ### Running Totals and Moving Averages
78
+
79
+ ```sql
80
+ SELECT
81
+ date,
82
+ revenue,
83
+ sum(revenue) OVER (ORDER BY date) AS running_total,
84
+ avg(revenue) OVER (
85
+ ORDER BY date
86
+ ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
87
+ ) AS moving_avg_7d
88
+ FROM daily_revenue;
89
+ ```
90
+
91
+ ### Lead/Lag (Access Adjacent Rows)
92
+
93
+ ```sql
94
+ SELECT
95
+ event_time,
96
+ event_type,
97
+ lag(event_time) OVER (PARTITION BY user_id ORDER BY event_time) AS prev_event,
98
+ event_time - lag(event_time) OVER (PARTITION BY user_id ORDER BY event_time) AS time_since_last
99
+ FROM user_events;
100
+ ```
101
+
102
+ ### First/Last Value
103
+
104
+ ```sql
105
+ SELECT DISTINCT
106
+ department,
107
+ first_value(name) OVER (
108
+ PARTITION BY department ORDER BY salary DESC
109
+ ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
110
+ ) AS highest_paid
111
+ FROM employees;
112
+ ```
113
+
114
+ ### Gaps and Islands
115
+
116
+ Find consecutive sequences:
117
+
118
+ ```sql
119
+ WITH numbered AS (
120
+ SELECT *,
121
+ date - (row_number() OVER (PARTITION BY user_id ORDER BY date))::int * interval '1 day' AS grp
122
+ FROM daily_logins
123
+ )
124
+ SELECT user_id, min(date) AS streak_start, max(date) AS streak_end,
125
+ count(*) AS streak_length
126
+ FROM numbered
127
+ GROUP BY user_id, grp
128
+ HAVING count(*) >= 7; -- streaks of 7+ days
129
+ ```
130
+
131
+ ## Lateral Joins
132
+
133
+ LATERAL lets a subquery reference columns from preceding tables. Essential for "top-N per group" queries.
134
+
135
+ ### Top-N Per Group
136
+
137
+ ```sql
138
+ -- Get latest 3 orders per customer
139
+ SELECT c.name, o.*
140
+ FROM customers c
141
+ CROSS JOIN LATERAL (
142
+ SELECT id, total, created_at
143
+ FROM orders
144
+ WHERE customer_id = c.id
145
+ ORDER BY created_at DESC
146
+ LIMIT 3
147
+ ) o;
148
+ ```
149
+
150
+ This is much faster than window function approaches when you have an index on `orders(customer_id, created_at DESC)`.
151
+
152
+ ### Calling Set-Returning Functions
153
+
154
+ ```sql
155
+ SELECT j.id, elem.key, elem.value
156
+ FROM journal_entries j
157
+ CROSS JOIN LATERAL jsonb_each_text(j.metadata) AS elem;
158
+ ```
159
+
160
+ ## Recursive Queries
161
+
162
+ ### Tree Traversal (Adjacency List)
163
+
164
+ ```sql
165
+ WITH RECURSIVE tree AS (
166
+ -- Base case: root nodes
167
+ SELECT id, name, parent_id, 0 AS depth, ARRAY[id] AS path
168
+ FROM categories
169
+ WHERE parent_id IS NULL
170
+
171
+ UNION ALL
172
+
173
+ -- Recursive step
174
+ SELECT c.id, c.name, c.parent_id, t.depth + 1, t.path || c.id
175
+ FROM categories c
176
+ JOIN tree t ON t.id = c.parent_id
177
+ WHERE NOT c.id = ANY(t.path) -- cycle prevention
178
+ )
179
+ SELECT * FROM tree ORDER BY path;
180
+ ```
181
+
182
+ ### Generating Series
183
+
184
+ ```sql
185
+ -- Date series for gap-filling
186
+ SELECT d::date, coalesce(o.total, 0) AS total
187
+ FROM generate_series('2024-01-01'::date, '2024-12-31'::date, '1 day') AS d
188
+ LEFT JOIN (
189
+ SELECT created_at::date AS day, sum(total) AS total
190
+ FROM orders
191
+ GROUP BY 1
192
+ ) o ON o.day = d;
193
+ ```
194
+
195
+ ## UPSERT (INSERT ON CONFLICT)
196
+
197
+ ### Basic Upsert
198
+
199
+ ```sql
200
+ INSERT INTO user_settings (user_id, key, value)
201
+ VALUES (1, 'theme', 'dark')
202
+ ON CONFLICT (user_id, key)
203
+ DO UPDATE SET
204
+ value = EXCLUDED.value,
205
+ updated_at = now();
206
+ ```
207
+
208
+ ### Insert-or-Ignore
209
+
210
+ ```sql
211
+ INSERT INTO tags (name)
212
+ VALUES ('postgres'), ('sql'), ('database')
213
+ ON CONFLICT (name) DO NOTHING;
214
+ ```
215
+
216
+ ### Upsert with Conditional Update
217
+
218
+ ```sql
219
+ INSERT INTO inventory (sku, quantity, last_restock)
220
+ VALUES ('ABC-123', 50, now())
221
+ ON CONFLICT (sku)
222
+ DO UPDATE SET
223
+ quantity = inventory.quantity + EXCLUDED.quantity,
224
+ last_restock = EXCLUDED.last_restock
225
+ WHERE inventory.quantity < 100; -- only restock if low
226
+ ```
227
+
228
+ ### Upsert Returning
229
+
230
+ ```sql
231
+ INSERT INTO users (email, name)
232
+ VALUES ('a@b.com', 'Alice')
233
+ ON CONFLICT (email)
234
+ DO UPDATE SET name = EXCLUDED.name
235
+ RETURNING id;
236
+ ```
237
+
238
+ Do not use `(xmax = 0)` as an inserted-versus-updated contract; it relies on implementation details. On PG18+, use `OLD`/`NEW` in `RETURNING`. On earlier versions, distinguish outcomes in application logic or use separate statements when the distinction matters.
239
+
240
+ ### OLD/NEW in RETURNING (PG18+)
241
+
242
+ All DML commands support `OLD` and `NEW` references in RETURNING, making it easy to see before/after values:
243
+
244
+ ```sql
245
+ UPDATE products SET price = price * 1.10
246
+ WHERE category = 'electronics'
247
+ RETURNING id, old.price AS old_price, new.price AS new_price;
248
+
249
+ DELETE FROM sessions WHERE expired_at < now()
250
+ RETURNING old.*;
251
+ ```
252
+
253
+ ## MERGE (PG15+)
254
+
255
+ SQL-standard command for conditional INSERT, UPDATE, or DELETE in a single statement. Replaces UPSERT for complex cases where you need different actions based on whether the row exists.
256
+
257
+ ```sql
258
+ MERGE INTO inventory AS target
259
+ USING incoming_shipment AS source
260
+ ON target.sku = source.sku
261
+ WHEN MATCHED AND source.quantity = 0 THEN
262
+ DELETE
263
+ WHEN MATCHED THEN
264
+ UPDATE SET quantity = target.quantity + source.quantity,
265
+ last_restock = now()
266
+ WHEN NOT MATCHED THEN
267
+ INSERT (sku, quantity, last_restock)
268
+ VALUES (source.sku, source.quantity, now());
269
+ ```
270
+
271
+ ### MERGE RETURNING (PG17+)
272
+
273
+ ```sql
274
+ MERGE INTO inventory AS target
275
+ USING incoming_shipment AS source
276
+ ON target.sku = source.sku
277
+ WHEN MATCHED THEN
278
+ UPDATE SET quantity = target.quantity + source.quantity
279
+ WHEN NOT MATCHED THEN
280
+ INSERT (sku, quantity) VALUES (source.sku, source.quantity)
281
+ RETURNING merge_action(), target.*;
282
+ -- merge_action() returns 'INSERT', 'UPDATE', or 'DELETE'
283
+ ```
284
+
285
+ **When to use MERGE vs UPSERT**: Use `INSERT ON CONFLICT` for simple insert-or-update on a single table. Use `MERGE` when you need different actions based on conditions, when the source is another table/query, or when you need DELETE as one of the outcomes.
286
+
287
+ ## JSON_TABLE (PG17+)
288
+
289
+ Convert JSON data to a relational table, usable in FROM:
290
+
291
+ ```sql
292
+ SELECT jt.*
293
+ FROM events,
294
+ JSON_TABLE(
295
+ payload, '$'
296
+ COLUMNS (
297
+ event_type text PATH '$.type',
298
+ city text PATH '$.address.city',
299
+ score int PATH '$.score'
300
+ )
301
+ ) AS jt
302
+ WHERE jt.event_type = 'click';
303
+ ```
304
+
305
+ ## Bulk Operations
306
+
307
+ ### Bulk Insert from Values
308
+
309
+ ```sql
310
+ INSERT INTO products (name, price, category)
311
+ VALUES
312
+ ('Widget A', 9.99, 'gadgets'),
313
+ ('Widget B', 14.99, 'gadgets'),
314
+ ('Widget C', 19.99, 'gadgets');
315
+ ```
316
+
317
+ ### Bulk Update with FROM
318
+
319
+ ```sql
320
+ UPDATE products p
321
+ SET price = new_prices.price
322
+ FROM (VALUES
323
+ (1, 12.99),
324
+ (2, 15.99),
325
+ (3, 22.99)
326
+ ) AS new_prices(id, price)
327
+ WHERE p.id = new_prices.id;
328
+ ```
329
+
330
+ ### Bulk Delete with Subquery
331
+
332
+ ```sql
333
+ DELETE FROM sessions
334
+ WHERE id IN (
335
+ SELECT id FROM sessions
336
+ WHERE last_active < now() - interval '30 days'
337
+ ORDER BY last_active
338
+ LIMIT 10000 -- batch to avoid long locks
339
+ );
340
+ ```
341
+
342
+ ## JSONB Queries
343
+
344
+ ### Querying JSONB
345
+
346
+ ```sql
347
+ -- Key access
348
+ SELECT payload->>'name' AS name FROM events; -- text
349
+ SELECT payload->'address'->'city' FROM events; -- jsonb
350
+ SELECT payload#>>'{address,city}' FROM events; -- text via path
351
+
352
+ -- Containment (uses GIN index)
353
+ SELECT * FROM events WHERE payload @> '{"type": "click"}';
354
+
355
+ -- Key existence
356
+ SELECT * FROM events WHERE payload ? 'error_code';
357
+
358
+ -- Array element access
359
+ SELECT payload->'tags'->>0 FROM events;
360
+ ```
361
+
362
+ ### JSONB Aggregation
363
+
364
+ ```sql
365
+ -- Build JSON object from rows
366
+ SELECT jsonb_object_agg(key, value) FROM settings WHERE user_id = 1;
367
+
368
+ -- Build JSON array from rows
369
+ SELECT jsonb_agg(jsonb_build_object('id', id, 'name', name))
370
+ FROM products
371
+ WHERE category = 'gadgets';
372
+ ```
373
+
374
+ ### JSONB Modification
375
+
376
+ ```sql
377
+ -- Set/overwrite a key
378
+ UPDATE events SET payload = payload || '{"processed": true}';
379
+
380
+ -- Remove a key
381
+ UPDATE events SET payload = payload - 'temp_field';
382
+
383
+ -- Set nested key
384
+ UPDATE events SET payload = jsonb_set(payload, '{status,code}', '"200"');
385
+ ```
386
+
387
+ ## Date/Time Patterns
388
+
389
+ ### JSONB Subscripting (PG14+)
390
+
391
+ Simpler syntax for JSONB access and assignment:
392
+
393
+ ```sql
394
+ -- Read JSONB (equivalent to payload->'address'->'city')
395
+ SELECT payload['address']['city'] FROM events;
396
+
397
+ -- Update (equivalent to jsonb_set)
398
+ UPDATE events SET payload['processed'] = 'true' WHERE id = 1;
399
+ UPDATE events SET payload['address']['zip'] = '"90210"' WHERE id = 1;
400
+ ```
401
+
402
+ ### date_bin() (PG14+)
403
+
404
+ Bin timestamps into uniform intervals — more flexible than `date_trunc`:
405
+
406
+ ```sql
407
+ -- 15-minute bins (date_trunc can only do hour/day/etc.)
408
+ SELECT
409
+ date_bin('15 minutes', created_at, '2024-01-01') AS bin,
410
+ count(*)
411
+ FROM orders
412
+ GROUP BY 1 ORDER BY 1;
413
+
414
+ -- 6-hour bins
415
+ SELECT date_bin('6 hours', occurred_at, '2024-01-01') AS bin, count(*)
416
+ FROM events GROUP BY 1;
417
+ ```
418
+
419
+ ### Truncation and Grouping
420
+
421
+ ```sql
422
+ SELECT
423
+ date_trunc('month', created_at) AS month,
424
+ count(*) AS orders
425
+ FROM orders
426
+ GROUP BY 1
427
+ ORDER BY 1;
428
+ ```
429
+
430
+ ### Interval Arithmetic
431
+
432
+ ```sql
433
+ SELECT * FROM subscriptions
434
+ WHERE expires_at BETWEEN now() AND now() + interval '7 days';
435
+ ```
436
+
437
+ ### Extract Components
438
+
439
+ ```sql
440
+ SELECT
441
+ extract(dow FROM created_at) AS day_of_week, -- 0=Sun, 6=Sat
442
+ extract(hour FROM created_at) AS hour,
443
+ count(*)
444
+ FROM orders
445
+ GROUP BY 1, 2;
446
+ ```
447
+
448
+ ## Concurrency Patterns
449
+
450
+ ### SKIP LOCKED (Queue Processing)
451
+
452
+ Multiple workers can process a queue table without blocking each other:
453
+
454
+ ```sql
455
+ -- Worker claims and processes next N items atomically
456
+ WITH next_batch AS (
457
+ SELECT id FROM job_queue
458
+ WHERE status = 'pending'
459
+ ORDER BY created_at
460
+ LIMIT 10
461
+ FOR UPDATE SKIP LOCKED
462
+ )
463
+ UPDATE job_queue SET status = 'processing', started_at = now()
464
+ WHERE id IN (SELECT id FROM next_batch)
465
+ RETURNING *;
466
+ ```
467
+
468
+ ### Deadlock Prevention
469
+
470
+ Always acquire row locks in a consistent order (e.g., by ID):
471
+
472
+ ```sql
473
+ -- Bad: two transactions locking rows in different order → deadlock
474
+ -- Good: always lock in ID order
475
+ SELECT * FROM accounts
476
+ WHERE id IN (5, 12, 3)
477
+ ORDER BY id
478
+ FOR UPDATE;
479
+ ```
480
+
481
+ ### Transaction Discipline
482
+
483
+ ```sql
484
+ -- Set statement timeout to prevent runaway queries
485
+ SET statement_timeout = '30s';
486
+
487
+ -- Kill idle-in-transaction sessions (holds locks, blocks VACUUM)
488
+ SET idle_in_transaction_session_timeout = '60s';
489
+
490
+ -- Limit total transaction duration (PG17+)
491
+ SET transaction_timeout = '5min';
492
+ ```
493
+
494
+ Keep transactions short: move external calls (HTTP, file I/O) outside the transaction boundary.
495
+
496
+ ### N+1 Query Elimination
497
+
498
+ ```sql
499
+ -- Bad: one query per item (N+1 pattern)
500
+ -- SELECT * FROM orders WHERE customer_id = 1;
501
+ -- SELECT * FROM orders WHERE customer_id = 2;
502
+ -- ...
503
+
504
+ -- Good: single query with ANY
505
+ SELECT * FROM orders WHERE customer_id = ANY($1::bigint[]);
506
+ -- Pass array of IDs: ARRAY[1, 2, 3, ...]
507
+ ```
508
+
509
+ ## Useful PG18+ Functions
510
+
511
+ ### array_sort() and array_reverse()
512
+
513
+ ```sql
514
+ SELECT array_sort(ARRAY[3, 1, 4, 1, 5]); -- {1, 1, 3, 4, 5}
515
+ SELECT array_reverse(ARRAY[1, 2, 3]); -- {3, 2, 1}
516
+ ```
517
+
518
+ ### casefold() — Unicode Case-Insensitive Matching
519
+
520
+ More robust than `lower()` for internationalized text:
521
+
522
+ ```sql
523
+ SELECT casefold('Hello World') = casefold('HELLO WORLD'); -- true
524
+ ```
525
+
526
+ ## Anti-Patterns to Avoid
527
+
528
+ ### SELECT * in Production Queries
529
+ Use explicit column lists. `SELECT *` breaks when columns change and prevents index-only scans.
530
+
531
+ ### NOT IN with NULLs
532
+ `NOT IN (subquery)` returns no rows if any subquery result is NULL. Use `NOT EXISTS` instead:
533
+
534
+ ```sql
535
+ -- Bad: breaks if orders.customer_id has any NULL
536
+ SELECT * FROM customers WHERE id NOT IN (SELECT customer_id FROM orders);
537
+
538
+ -- Good: always correct
539
+ SELECT * FROM customers c
540
+ WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id);
541
+ ```
542
+
543
+ ### Implicit Casts in WHERE Clauses
544
+ Casting a column prevents index use:
545
+
546
+ ```sql
547
+ -- Bad: casts every row, no index
548
+ WHERE created_at::date = '2024-01-15'
549
+
550
+ -- Good: range scan, uses index
551
+ WHERE created_at >= '2024-01-15' AND created_at < '2024-01-16'
552
+ ```
553
+
554
+ ### ORDER BY on Unindexed Large Result Sets
555
+ If you ORDER BY + LIMIT on a large table, ensure there's an index on the ORDER BY columns to avoid a full sort.
556
+
557
+ ### Using OFFSET for Pagination
558
+ OFFSET scans and discards rows. Use keyset pagination instead:
559
+
560
+ ```sql
561
+ -- Bad: slow at high offsets
562
+ SELECT * FROM products ORDER BY id LIMIT 20 OFFSET 10000;
563
+
564
+ -- Good: keyset pagination
565
+ SELECT * FROM products WHERE id > $last_seen_id ORDER BY id LIMIT 20;
566
+ ```