<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Fundamentals on DPG — Declarative PG</title><link>https://thec1oud.github.io/dpg/docs/fundamentals/</link><description>Recent content in Fundamentals on DPG — Declarative PG</description><generator>Hugo</generator><language>en</language><atom:link href="https://thec1oud.github.io/dpg/docs/fundamentals/index.xml" rel="self" type="application/rss+xml"/><item><title>Two-Part Syntax</title><link>https://thec1oud.github.io/dpg/docs/fundamentals/two-part-syntax/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://thec1oud.github.io/dpg/docs/fundamentals/two-part-syntax/</guid><description>&lt;p>Every DPG object has at most two parts: native PostgreSQL DDL with the &lt;code>CREATE&lt;/code> verb removed (Part 1), and an optional &lt;code>{ }&lt;/code> block for things PostgreSQL expresses as separate statements (Part 2).&lt;/p>
&lt;p>&lt;strong>Rule of thumb:&lt;/strong> if PostgreSQL writes it as part of &lt;code>CREATE OBJECT&lt;/code>, it is Part 1. If PostgreSQL writes it as a separate statement (&lt;code>CREATE INDEX&lt;/code>, &lt;code>GRANT&lt;/code>, &lt;code>COMMENT ON&lt;/code>), it is Part 2.&lt;/p>
&lt;h2 id="basic-object--part-1-only">Basic object — Part 1 only&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">TABLE&lt;/span>&lt;span style="color:#fff"> &lt;/span>simple_log&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>id&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">BIGINT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">GENERATED&lt;/span>&lt;span style="color:#fff"> &lt;/span>ALWAYS&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">AS&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">IDENTITY&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">PRIMARY&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">KEY&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>message&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">TEXT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NOT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NULL&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">-- emits
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">CREATE&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">TABLE&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;public&amp;#34;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#0a3069">&amp;#34;simple_log&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;id&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">bigint&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">GENERATED&lt;/span>&lt;span style="color:#fff"> &lt;/span>ALWAYS&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">AS&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">IDENTITY&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">CONSTRAINT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;simple_log_pkey&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">PRIMARY&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">KEY&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;message&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">text&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NOT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NULL&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="object-with-a---block--parts-1-and-2">Object with a &lt;code>{ }&lt;/code> block — Parts 1 and 2&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">TABLE&lt;/span>&lt;span style="color:#fff"> &lt;/span>users&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>id&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">BIGINT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">GENERATED&lt;/span>&lt;span style="color:#fff"> &lt;/span>ALWAYS&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">AS&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">IDENTITY&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>email&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">TEXT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NOT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NULL&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">CONSTRAINT&lt;/span>&lt;span style="color:#fff"> &lt;/span>pk_users&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">PRIMARY&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">KEY&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>id&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">CONSTRAINT&lt;/span>&lt;span style="color:#fff"> &lt;/span>uq_users_email&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">UNIQUE&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>email&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">COMMENT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;Primary identity store&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">OWNER&lt;/span>&lt;span style="color:#fff"> &lt;/span>app_role&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>INDEXES&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">{&lt;/span>&lt;span style="color:#fff"> &lt;/span>idx_email&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>email&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>GRANTS&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">{&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">SELECT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">TO&lt;/span>&lt;span style="color:#fff"> &lt;/span>app_readonly&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">-- emits
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">CREATE&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">TABLE&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;public&amp;#34;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#0a3069">&amp;#34;users&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;id&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">bigint&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">GENERATED&lt;/span>&lt;span style="color:#fff"> &lt;/span>ALWAYS&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">AS&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">IDENTITY&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;email&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">text&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NOT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NULL&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">CONSTRAINT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;pk_users&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">PRIMARY&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">KEY&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;id&amp;#34;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">CONSTRAINT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;uq_users_email&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">UNIQUE&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;email&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">CREATE&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">INDEX&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;idx_email&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">ON&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;public&amp;#34;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#0a3069">&amp;#34;users&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;email&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">COMMENT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">ON&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">TABLE&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;public&amp;#34;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#0a3069">&amp;#34;users&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">IS&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;Primary identity store&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">ALTER&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">TABLE&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;public&amp;#34;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#0a3069">&amp;#34;users&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">OWNER&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">TO&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;app_role&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">GRANT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">SELECT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">ON&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">TABLE&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;public&amp;#34;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#0a3069">&amp;#34;users&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">TO&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;app_readonly&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Since &lt;code>idx_email&lt;/code> is declared alongside its own brand-new table, it&amp;rsquo;s created inside the same transaction as the &lt;code>CREATE TABLE&lt;/code> — PostgreSQL rejects &lt;code>CREATE INDEX CONCURRENTLY&lt;/code> inside a transaction block, so DPG never emits &lt;code>CONCURRENTLY&lt;/code> here, even if the index had written it explicitly. See &lt;a href="../../schema-objects/tables/indexes/">Indexes&lt;/a> for &lt;code>CONCURRENTLY&lt;/code> on indexes added to an already-existing table.&lt;/p></description></item><item><title>Project Structure</title><link>https://thec1oud.github.io/dpg/docs/fundamentals/project-structure/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://thec1oud.github.io/dpg/docs/fundamentals/project-structure/</guid><description>&lt;p>A DPG project maps one-to-one onto the topology of a PostgreSQL deployment. The directory structure encodes clusters and databases; &lt;code>.dpg&lt;/code> files are scoped to their containing database automatically.&lt;/p>
&lt;h2 id="directory-layout">Directory layout&lt;/h2>
&lt;pre tabindex="0">&lt;code>myproject/
├── dpg.toml # root config
│
├── production/ # cluster directory
│ ├── dpg.toml # cluster config (connection URL, options)
│ ├── cluster/ # cluster-level objects (roles, tablespaces)
│ │ ├── roles.dpg
│ │ └── tablespaces.dpg
│ │
│ └── myapp/ # database directory
│ ├── dpg.toml # database config (name, default schema)
│ ├── extensions.dpg
│ └── schemas/
│ └── public/
│ ├── types.dpg
│ ├── tables/
│ │ ├── users.dpg
│ │ └── orders.dpg
│ ├── views.dpg
│ └── functions.dpg
│
└── .dpg/
 ├── snapshots/
 │ └── production/
 │ └── myapp.json # committed snapshot — source of truth for diffing
 └── migrations/
 └── production/
 └── myapp/
 ├── 20260101T120000Z-4f0c2b9e1d7a.sql # migration log (committed)
 └── 20260101T120000Z-4f0c2b9e1d7a.json
&lt;/code>&lt;/pre>&lt;p>&lt;strong>Discovery rules:&lt;/strong>&lt;/p></description></item><item><title>Macros</title><link>https://thec1oud.github.io/dpg/docs/fundamentals/macros/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://thec1oud.github.io/dpg/docs/fundamentals/macros/</guid><description>&lt;p>Macros are source-level text fragments defined once and spread inline at any number of call sites. The preprocessor expands them before parsing — the compiler sees only the expanded result.&lt;/p>
&lt;p>&lt;code>MACRO&lt;/code> declarations generate no SQL. They must appear at the top level of a &lt;code>.dpg&lt;/code> file, not inside blocks.&lt;/p>
&lt;h2 id="paren-body-macro--column-fragments">Paren-body macro — column fragments&lt;/h2>
&lt;p>A paren-body macro spreads into a &lt;code>( )&lt;/code> column list.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>MACRO&lt;span style="color:#fff"> &lt;/span>common_timestamps&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>created_at&lt;span style="color:#fff"> &lt;/span>TIMESTAMPTZ&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NOT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NULL&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">DEFAULT&lt;/span>&lt;span style="color:#fff"> &lt;/span>now&lt;span style="color:#1f2328">(),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>updated_at&lt;span style="color:#fff"> &lt;/span>TIMESTAMPTZ&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">TABLE&lt;/span>&lt;span style="color:#fff"> &lt;/span>accounts&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>id&lt;span style="color:#fff"> &lt;/span>UUID&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NOT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NULL&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">DEFAULT&lt;/span>&lt;span style="color:#fff"> &lt;/span>gen_random_uuid&lt;span style="color:#1f2328">(),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>name&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">TEXT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NOT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NULL&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">...&lt;/span>common_timestamps&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">CONSTRAINT&lt;/span>&lt;span style="color:#fff"> &lt;/span>pk_accounts&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">PRIMARY&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">KEY&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>id&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">-- emits (macro expanded inline)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">CREATE&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">TABLE&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;public&amp;#34;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#0a3069">&amp;#34;accounts&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;id&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>uuid&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NOT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NULL&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">DEFAULT&lt;/span>&lt;span style="color:#fff"> &lt;/span>gen_random_uuid&lt;span style="color:#1f2328">(),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;name&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">text&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NOT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NULL&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;created_at&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>timestamptz&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NOT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">NULL&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">DEFAULT&lt;/span>&lt;span style="color:#fff"> &lt;/span>now&lt;span style="color:#1f2328">(),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;updated_at&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>timestamptz&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">CONSTRAINT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;pk_accounts&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">PRIMARY&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">KEY&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;id&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="brace-body-macro--block-fragments">Brace-body macro — block fragments&lt;/h2>
&lt;p>A brace-body macro spreads into a &lt;code>{ }&lt;/code> block.&lt;/p></description></item><item><title>Snapshots &amp; Diffing</title><link>https://thec1oud.github.io/dpg/docs/fundamentals/snapshots/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://thec1oud.github.io/dpg/docs/fundamentals/snapshots/</guid><description>&lt;p>DPG never requires a live database connection to generate a migration. The primary workflow diffs &lt;code>.dpg&lt;/code> source files against a committed JSON snapshot.&lt;/p>
&lt;h2 id="workflow">Workflow&lt;/h2>
&lt;pre tabindex="0">&lt;code>.dpg source files ──compile──▶ desired state
 │
 ▼ diff
.dpg/snapshots/prod/myapp.json ───────▶│
 ▼
 migration SQL
&lt;/code>&lt;/pre>&lt;p>&lt;code>dpg apply&lt;/code> executes the SQL, records it in the migration log and updates the snapshot atomically. The snapshot is always the post-apply state.&lt;/p>
&lt;h2 id="migration-log">Migration log&lt;/h2>
&lt;p>The snapshot says what state the source has been migrated to; the migration log says how a database gets there. Each migration is &lt;code>&amp;lt;id&amp;gt;.sql&lt;/code> (the SQL as &lt;code>dpg plan&lt;/code> prints it) beside &lt;code>&amp;lt;id&amp;gt;.json&lt;/code>, which names the migration it follows and the snapshot change it made:&lt;/p></description></item><item><title>Name Maps</title><link>https://thec1oud.github.io/dpg/docs/fundamentals/name-maps/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://thec1oud.github.io/dpg/docs/fundamentals/name-maps/</guid><description>&lt;p>Name Maps let you annotate DPG schema objects with the naming convention each downstream tool should apply to them. ORM generators (Prisma, Drizzle), type-safe query builders (sqlc), and API code generators can read these annotations from the snapshot and produce identifiers in the right casing for their target language — without touching the DPG source.&lt;/p>
&lt;p>Name maps are &lt;strong>metadata only&lt;/strong>: they do not affect generated PostgreSQL DDL and produce no SQL migration steps. They are serialised into the snapshot JSON for downstream consumers.&lt;/p></description></item></channel></rss>