diff --git a/.github/workflows/cd-marketplace.yml b/.github/workflows/cd-marketplace.yml index 4e39186..ecb65f0 100644 --- a/.github/workflows/cd-marketplace.yml +++ b/.github/workflows/cd-marketplace.yml @@ -159,6 +159,9 @@ jobs: npm install fi + - name: Run tests + run: npm test + - name: Package extension env: VSIX: ${{ steps.pkg.outputs.vsix }} diff --git a/.github/workflows/cd-prerelease.yml b/.github/workflows/cd-prerelease.yml index 4dc62ac..388d25b 100644 --- a/.github/workflows/cd-prerelease.yml +++ b/.github/workflows/cd-prerelease.yml @@ -150,6 +150,9 @@ jobs: npm install fi + - name: Run tests + run: npm test + - name: Package extension env: VSIX: ${{ steps.pkg.outputs.vsix }} diff --git a/.vscode/settings.json b/.vscode/settings.json index 4c162cd..b83350d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,17 +12,14 @@ }, "json.schemas": [ { - "fileMatch": [ - "*.model.json" - ], + "fileMatch": ["*.model.json"], "url": ".dj/schemas/model.schema.json" }, { - "fileMatch": [ - "*.source.json" - ], + "fileMatch": ["*.source.json"], "url": ".dj/schemas/source.schema.json" } ], + "dj.dbtProjectNames": ["jaffle_shop"], "dj.dataExplorer.autoRefresh": false } diff --git a/.vscodeignore b/.vscodeignore index d5b4052..f50df64 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -27,12 +27,20 @@ web/ .eslintrc.json .eslintcache .gitignore +.markdownlint.json .prettierrc .prettierignore +.tagignore + +CONTRIBUTORS.md +DEVELOPMENT_SETUP.md +Makefile +ROADMAP.md Dockerfile esbuild.mjs eslint.config.mjs +jest.config.js jest.config.ts tsconfig.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a9ff8a..41f322e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## 2.5.0 +### Model Wizard + +- **Create and edit models with `materialization` instead of deprecated top-level fields.** The wizard writes `materialization` (string or nested strategy/partitions) rather than `materialized`, `incremental_strategy`, and `partitioned_by`. Saving an edit removes those legacy keys from the file. jaffle_shop examples use the new shape. + ### Framework - **Dynamic Lightdash custom granularities and expanded time intervals.** Custom time granularities defined in `lightdash.config.yml` (under `custom_granularities`) are dynamically discovered and loaded into model schemas and editor autocomplete. Built-in time intervals also now include `MINUTE`, `SECOND`, and `MILLISECOND`. diff --git a/docs/examples/jaffle_shop/models/staging/customers/profiles/stg__customers__profiles__clean.model.json b/docs/examples/jaffle_shop/models/staging/customers/profiles/stg__customers__profiles__clean.model.json index 5eb44fc..7bcd69c 100644 --- a/docs/examples/jaffle_shop/models/staging/customers/profiles/stg__customers__profiles__clean.model.json +++ b/docs/examples/jaffle_shop/models/staging/customers/profiles/stg__customers__profiles__clean.model.json @@ -3,7 +3,7 @@ "group": "customers", "topic": "profiles", "name": "clean", - "materialized": "ephemeral", + "materialization": "ephemeral", "from": { "source": "development__jaffle_shop_dev_seeds.raw_customers" }, diff --git a/docs/examples/jaffle_shop/models/staging/products/catalog/stg__products__catalog__catalog.model.json b/docs/examples/jaffle_shop/models/staging/products/catalog/stg__products__catalog__catalog.model.json index dd5dbde..4917810 100644 --- a/docs/examples/jaffle_shop/models/staging/products/catalog/stg__products__catalog__catalog.model.json +++ b/docs/examples/jaffle_shop/models/staging/products/catalog/stg__products__catalog__catalog.model.json @@ -3,7 +3,7 @@ "group": "products", "topic": "catalog", "name": "catalog", - "materialized": "ephemeral", + "materialization": "ephemeral", "from": { "source": "development__jaffle_shop_dev_seeds.raw_products" }, diff --git a/docs/examples/jaffle_shop/models/staging/sales/items/stg__sales__items__order_details.model.json b/docs/examples/jaffle_shop/models/staging/sales/items/stg__sales__items__order_details.model.json index a7a0658..41bd159 100644 --- a/docs/examples/jaffle_shop/models/staging/sales/items/stg__sales__items__order_details.model.json +++ b/docs/examples/jaffle_shop/models/staging/sales/items/stg__sales__items__order_details.model.json @@ -3,7 +3,7 @@ "group": "sales", "topic": "items", "name": "order_details", - "materialized": "ephemeral", + "materialization": "ephemeral", "from": { "source": "development__jaffle_shop_dev_seeds.raw_items" }, diff --git a/docs/examples/jaffle_shop/models/staging/sales/orders/stg__sales__orders__standardized.model.json b/docs/examples/jaffle_shop/models/staging/sales/orders/stg__sales__orders__standardized.model.json index 94a1941..9f05c63 100644 --- a/docs/examples/jaffle_shop/models/staging/sales/orders/stg__sales__orders__standardized.model.json +++ b/docs/examples/jaffle_shop/models/staging/sales/orders/stg__sales__orders__standardized.model.json @@ -3,7 +3,7 @@ "group": "sales", "topic": "orders", "name": "standardized", - "materialized": "ephemeral", + "materialization": "ephemeral", "from": { "source": "development__jaffle_shop_dev_seeds.raw_orders" }, diff --git a/docs/examples/jaffle_shop/models/staging/sales/stores/stg__sales__stores__locations.model.json b/docs/examples/jaffle_shop/models/staging/sales/stores/stg__sales__stores__locations.model.json index b1f2537..1f7fbac 100644 --- a/docs/examples/jaffle_shop/models/staging/sales/stores/stg__sales__stores__locations.model.json +++ b/docs/examples/jaffle_shop/models/staging/sales/stores/stg__sales__stores__locations.model.json @@ -3,7 +3,7 @@ "group": "sales", "topic": "stores", "name": "locations", - "materialized": "ephemeral", + "materialization": "ephemeral", "from": { "source": "development__jaffle_shop_dev_seeds.raw_stores" }, diff --git a/docs/examples/jaffle_shop/models/staging/supply_chain/supplies/stg__supply_chain__supplies__inventory.model.json b/docs/examples/jaffle_shop/models/staging/supply_chain/supplies/stg__supply_chain__supplies__inventory.model.json index 8bd8f90..5cf46a6 100644 --- a/docs/examples/jaffle_shop/models/staging/supply_chain/supplies/stg__supply_chain__supplies__inventory.model.json +++ b/docs/examples/jaffle_shop/models/staging/supply_chain/supplies/stg__supply_chain__supplies__inventory.model.json @@ -3,7 +3,7 @@ "group": "supply_chain", "topic": "supplies", "name": "inventory", - "materialized": "ephemeral", + "materialization": "ephemeral", "from": { "source": "development__jaffle_shop_dev_seeds.raw_supplies" }, diff --git a/docs/examples/jaffle_shop_lightdash/models/staging/customers/profiles/stg__customers__profiles__clean.model.json b/docs/examples/jaffle_shop_lightdash/models/staging/customers/profiles/stg__customers__profiles__clean.model.json index 01cc216..8ae9b41 100644 --- a/docs/examples/jaffle_shop_lightdash/models/staging/customers/profiles/stg__customers__profiles__clean.model.json +++ b/docs/examples/jaffle_shop_lightdash/models/staging/customers/profiles/stg__customers__profiles__clean.model.json @@ -3,7 +3,7 @@ "group": "customers", "topic": "profiles", "name": "clean", - "materialized": "ephemeral", + "materialization": "ephemeral", "from": { "source": "development__jaffle_shop_lightdash_dev_seeds.raw_customers" }, diff --git a/docs/examples/jaffle_shop_lightdash/models/staging/products/catalog/stg__products__catalog__catalog.model.json b/docs/examples/jaffle_shop_lightdash/models/staging/products/catalog/stg__products__catalog__catalog.model.json index bdc763a..9969419 100644 --- a/docs/examples/jaffle_shop_lightdash/models/staging/products/catalog/stg__products__catalog__catalog.model.json +++ b/docs/examples/jaffle_shop_lightdash/models/staging/products/catalog/stg__products__catalog__catalog.model.json @@ -3,7 +3,7 @@ "group": "products", "topic": "catalog", "name": "catalog", - "materialized": "ephemeral", + "materialization": "ephemeral", "from": { "source": "development__jaffle_shop_lightdash_dev_seeds.raw_products" }, diff --git a/docs/examples/jaffle_shop_lightdash/models/staging/sales/items/stg__sales__items__order_details.model.json b/docs/examples/jaffle_shop_lightdash/models/staging/sales/items/stg__sales__items__order_details.model.json index 54cf7b5..92ed3be 100644 --- a/docs/examples/jaffle_shop_lightdash/models/staging/sales/items/stg__sales__items__order_details.model.json +++ b/docs/examples/jaffle_shop_lightdash/models/staging/sales/items/stg__sales__items__order_details.model.json @@ -3,7 +3,7 @@ "group": "sales", "topic": "items", "name": "order_details", - "materialized": "ephemeral", + "materialization": "ephemeral", "from": { "source": "development__jaffle_shop_lightdash_dev_seeds.raw_items" }, diff --git a/docs/examples/jaffle_shop_lightdash/models/staging/sales/orders/stg__sales__orders__standardized.model.json b/docs/examples/jaffle_shop_lightdash/models/staging/sales/orders/stg__sales__orders__standardized.model.json index 5af74d9..e197b28 100644 --- a/docs/examples/jaffle_shop_lightdash/models/staging/sales/orders/stg__sales__orders__standardized.model.json +++ b/docs/examples/jaffle_shop_lightdash/models/staging/sales/orders/stg__sales__orders__standardized.model.json @@ -3,7 +3,7 @@ "group": "sales", "topic": "orders", "name": "standardized", - "materialized": "ephemeral", + "materialization": "ephemeral", "from": { "source": "development__jaffle_shop_lightdash_dev_seeds.raw_orders" }, diff --git a/docs/examples/jaffle_shop_lightdash/models/staging/sales/stores/stg__sales__stores__locations.model.json b/docs/examples/jaffle_shop_lightdash/models/staging/sales/stores/stg__sales__stores__locations.model.json index 1d21471..521db9e 100644 --- a/docs/examples/jaffle_shop_lightdash/models/staging/sales/stores/stg__sales__stores__locations.model.json +++ b/docs/examples/jaffle_shop_lightdash/models/staging/sales/stores/stg__sales__stores__locations.model.json @@ -3,7 +3,7 @@ "group": "sales", "topic": "stores", "name": "locations", - "materialized": "ephemeral", + "materialization": "ephemeral", "from": { "source": "development__jaffle_shop_lightdash_dev_seeds.raw_stores" }, diff --git a/docs/examples/jaffle_shop_lightdash/models/staging/supply_chain/supplies/stg__supply_chain__supplies__inventory.model.json b/docs/examples/jaffle_shop_lightdash/models/staging/supply_chain/supplies/stg__supply_chain__supplies__inventory.model.json index 2fbceb7..4f7147c 100644 --- a/docs/examples/jaffle_shop_lightdash/models/staging/supply_chain/supplies/stg__supply_chain__supplies__inventory.model.json +++ b/docs/examples/jaffle_shop_lightdash/models/staging/supply_chain/supplies/stg__supply_chain__supplies__inventory.model.json @@ -3,7 +3,7 @@ "group": "supply_chain", "topic": "supplies", "name": "inventory", - "materialized": "ephemeral", + "materialization": "ephemeral", "from": { "source": "development__jaffle_shop_lightdash_dev_seeds.raw_supplies" }, diff --git a/package-lock.json b/package-lock.json index 89b1c6b..e14f80e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -147,16 +147,6 @@ "node": ">=22.0.0" } }, - "node_modules/@azure/core-process": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@azure/core-process/-/core-process-1.0.0.tgz", - "integrity": "sha512-/shnJ+ooO8WPxDhPEeI/2oRQuubn16gZ6CvlbpWbEswZfzwI9tI/sMAHmF3x1LuQ9yZYXfLW3TjzGMLEC5blKg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.0.0" - } - }, "node_modules/@azure/core-rest-pipeline": { "version": "1.25.0", "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.25.0.tgz", @@ -205,27 +195,26 @@ } }, "node_modules/@azure/identity": { - "version": "4.13.3", - "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.13.3.tgz", - "integrity": "sha512-zGQPtqvXPgSA8yfV2CkIQ1qirqk0p9AIVpC5uEkdXQYcKl07QHvyaGYRnZOk0AsQUmxNb4wfkcwY5di8Z5xa9A==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.13.0.tgz", + "integrity": "sha512-uWC0fssc+hs1TGGVkkghiaFkkS7NkTxfnCH+Hdg+yTehTpMcehpok4PgUKKdyCH+9ldu6FhiHRv84Ntqj1vVcw==", "dev": true, "license": "MIT", "dependencies": { "@azure/abort-controller": "^2.0.0", "@azure/core-auth": "^1.9.0", "@azure/core-client": "^1.9.2", - "@azure/core-process": "^1.0.0", "@azure/core-rest-pipeline": "^1.17.0", "@azure/core-tracing": "^1.0.0", "@azure/core-util": "^1.11.0", "@azure/logger": "^1.0.0", - "@azure/msal-browser": "^5.5.0", - "@azure/msal-node": "^6.0.0", + "@azure/msal-browser": "^4.2.0", + "@azure/msal-node": "^3.5.0", "open": "^10.1.0", "tslib": "^2.2.0" }, "engines": { - "node": ">=22.0.0" + "node": ">=20.0.0" } }, "node_modules/@azure/logger": { @@ -243,22 +232,22 @@ } }, "node_modules/@azure/msal-browser": { - "version": "5.24.0", - "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-5.24.0.tgz", - "integrity": "sha512-jS1stt81tslcVZi7fqVD+g6vr8w/IWqFl/vAB2dx/6EOroQDuCR4+z0o3C+d6a/GpLATvdoO+kwnDcYzsBXKQA==", + "version": "4.30.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.30.0.tgz", + "integrity": "sha512-HBBKfbZkMVzzF5bofvS1cXuNHFVc+gt4/HOnCmG/0hsHuZRJvJvDg/+7nTwIpoqvJc8BQp5o23rBUfisOLxR+w==", "dev": true, "license": "MIT", "dependencies": { - "@azure/msal-common": "16.14.2" + "@azure/msal-common": "15.17.0" }, "engines": { "node": ">=0.8.0" } }, "node_modules/@azure/msal-common": { - "version": "16.14.2", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-16.14.2.tgz", - "integrity": "sha512-HOBR0Gfo39TMrkxNG8k6cfjRkrRjXZc3JQs3ebMWQc9S4cihuknMYra3sgmzbZB752oQBqBN9+WF7c826p2vIQ==", + "version": "15.17.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.17.0.tgz", + "integrity": "sha512-VQ5/gTLFADkwue+FohVuCqlzFPUq4xSrX8jeZe+iwZuY6moliNC8xt86qPVNYdtbQfELDf2Nu6LI+demFPHGgw==", "dev": true, "license": "MIT", "engines": { @@ -266,27 +255,29 @@ } }, "node_modules/@azure/msal-node": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-6.0.1.tgz", - "integrity": "sha512-ixSO1Y/kCVRthRs+hSx/5qkwaunX1/RAePhlMN0wIpIQ4WEZ6AREGGnGd1AP0qspHVsAwzWQKGubpjh50JyJIQ==", + "version": "3.8.10", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.8.10.tgz", + "integrity": "sha512-0Hz7Kx4hs70KZWep/Rd7aw/qOLUF92wUOhn7ZsOuB5xNR/06NL1E2RAI9+UKH1FtvN8nD6mFjH7UKSjv6vOWvQ==", "dev": true, "license": "MIT", "dependencies": { - "@azure/msal-common": "16.14.1", - "jsonwebtoken": "^9.0.0" + "@azure/msal-common": "15.17.0", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.0" }, "engines": { - "node": ">=20" + "node": ">=16" } }, - "node_modules/@azure/msal-node/node_modules/@azure/msal-common": { - "version": "16.14.1", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-16.14.1.tgz", - "integrity": "sha512-Or6xhPNyi4zHW25158yxBoyxuCqNSPa5YBVqfF1J5Ks4MJWBo/USXdp05DQIPu1Zli00YZu6t0+h6KvHJealxQ==", + "node_modules/@azure/msal-node/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.8.0" + "bin": { + "uuid": "dist/bin/uuid" } }, "node_modules/@babel/code-frame": { @@ -6065,9 +6056,9 @@ } }, "node_modules/dompurify": { - "version": "3.4.16", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.16.tgz", - "integrity": "sha512-sqo+pNp3qRhCIpbgRi1y8Tgk27Bo2Ry7w0dC1NBeNTdZChWjz9Xb/KOoZbRP/R6pQZ80Qw8YhXw13hWWBbMRnQ==", + "version": "3.4.17", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.17.tgz", + "integrity": "sha512-B/pSlYVHQ58kqISD/yDjuJ1yfzI34m1gF4lAod2bwSRhiN4K5Cl3H8Af7hqB2PmTL911tdEudnnXn5FnhRoz0w==", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" @@ -7004,9 +6995,9 @@ "integrity": "sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw==" }, "node_modules/fast-uri": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", - "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.9.tgz", + "integrity": "sha512-hS/0Wt3Ya043oKXs0sIxrMpKQITXhMLIrVAKKXi4gozGC9v7YRWVnXIZzjNPTO02M9BdxLCWqK1yRXgNziVyJQ==", "funding": [ { "type": "github", @@ -9835,9 +9826,9 @@ } }, "node_modules/markdown-it": { - "version": "14.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.3.2.tgz", - "integrity": "sha512-sHHjZ5fJKlgrG4qns2YwVcdNep35h5fERrfkD2YNsb9UFk0UIHarbiTaHKVMlPuWAoiilyK8Fv/jAm11slsY7Q==", + "version": "14.3.3", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.3.3.tgz", + "integrity": "sha512-L//tDAkjTjJCU6pBUSBTgs3Kg4InVaZuUZog/b6V12UKhcDQ7S78877ibbCanRExwPuYP1CZD7Gd2dxSy1GXRg==", "dev": true, "funding": [ { @@ -11139,9 +11130,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz", - "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==", + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.5.tgz", + "integrity": "sha512-TEHFzb5KRDKaOgJ4TYE+0jyJtFbjLvkdVOu0fZ2b6MTWzoqZd4Le+61aEppWkvTlYePgOX4ATL1wsAIPMLTw6Q==", "dev": true, "license": "MIT", "dependencies": { @@ -14239,9 +14230,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "7.30.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.30.0.tgz", - "integrity": "sha512-dkrQXeHSaoamnItlYbmzG0wFYrM0ZwDxCIg0A7aKjTyyhh9svRzCNFEzV+Vm05/yehjCzjDZ31KXfGEjYSztDQ==", + "version": "7.30.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.30.1.tgz", + "integrity": "sha512-03KrMbjIFDWQR5RNPrSw3bd1r12JpyFQl9/yxjUbJtqkjmllqC5lFjZh6ujeuJCKr8EOQvRW872Oy/az+nLYxg==", "dev": true, "license": "MIT", "engines": { @@ -15362,9 +15353,9 @@ } }, "node_modules/zod": { - "version": "4.6.5", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz", - "integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==", + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.7.tgz", + "integrity": "sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==", "dev": true, "license": "MIT", "funding": { diff --git a/package.json b/package.json index 532126d..821f66e 100644 --- a/package.json +++ b/package.json @@ -1054,4 +1054,4 @@ "brace-expansion@2": "^2.1.7", "brace-expansion@5": "^5.0.12" } -} \ No newline at end of file +} diff --git a/schemas/model.sql_hooks.schema.json b/schemas/model.sql_hooks.schema.json index 45a244a..8855f24 100644 --- a/schemas/model.sql_hooks.schema.json +++ b/schemas/model.sql_hooks.schema.json @@ -20,7 +20,7 @@ ] }, "pre": { - "description": "Statement(s) to run before model", + "description": "Statement(s) to run before the model. Omit to use DJ's incremental session pre-hook. null disables that hook. A string or array replaces it.", "anyOf": [ { "type": "string" @@ -31,6 +31,9 @@ "items": { "type": "string" } + }, + { + "type": "null" } ] } diff --git a/src/bin/dj-cli.ts b/src/bin/dj-cli.ts index ae98c32..110ee8d 100644 --- a/src/bin/dj-cli.ts +++ b/src/bin/dj-cli.ts @@ -19,17 +19,17 @@ * * Exit codes: 0 ok · 1 operation error · 2 usage/bad-input · 3 no live endpoint · 4 timeout */ -import type { - EndpointDescriptor, - RpcRequest, - RpcResponse, -} from '@shared/cli/types'; import { mergeCliPayload } from '@shared/cli/mergePayload'; import { CLI_USAGE, formatGlobalHelp, formatOperationHelpSummary, } from '@shared/cli/operationHelp'; +import type { + EndpointDescriptor, + RpcRequest, + RpcResponse, +} from '@shared/cli/types'; import * as fs from 'fs'; import * as net from 'net'; import * as path from 'path'; diff --git a/src/services/cliBridge/CliBridgeServer.ts b/src/services/cliBridge/CliBridgeServer.ts index a38fc5f..c8335da 100644 --- a/src/services/cliBridge/CliBridgeServer.ts +++ b/src/services/cliBridge/CliBridgeServer.ts @@ -97,9 +97,7 @@ export class CliBridgeServer { /* not present — fine */ } - this.server = net.createServer((socket) => - this.handleConnection(socket), - ); + this.server = net.createServer((socket) => this.handleConnection(socket)); this.server.on('error', (err) => this.opts.log.error('[dj-bridge] server error:', err), ); diff --git a/src/services/cliBridge/__tests__/operationRegistry.test.ts b/src/services/cliBridge/__tests__/operationRegistry.test.ts index 11b91ee..3168e80 100644 --- a/src/services/cliBridge/__tests__/operationRegistry.test.ts +++ b/src/services/cliBridge/__tests__/operationRegistry.test.ts @@ -63,9 +63,7 @@ describe('operationRegistry — read tier', () => { const { ctx, calls } = makeCtx(); const input = { catalog: 'c', schema: 's', table: 't' }; await dispatch(reg, 'trino.columns', input, ctx); - expect(calls).toEqual([ - { type: 'trino-fetch-columns', request: input }, - ]); + expect(calls).toEqual([{ type: 'trino-fetch-columns', request: input }]); }); it('accepts an explicit { request } envelope as an escape hatch', async () => { @@ -82,14 +80,22 @@ describe('operationRegistry — read tier', () => { const { ctx, calls } = makeCtx(['analytics']); await dispatch(reg, 'dbt.models', null, ctx); expect(calls).toEqual([ - { type: 'dbt-fetch-available-models', request: { projectName: 'analytics' } }, + { + type: 'dbt-fetch-available-models', + request: { projectName: 'analytics' }, + }, ]); }); it('honors an explicit projectName when provided', async () => { const reg = createOperationRegistry(); const { ctx, calls } = makeCtx(['a', 'b']); - await dispatch(reg, 'dbt.compiled-status', { modelName: 'm', projectName: 'b' }, ctx); + await dispatch( + reg, + 'dbt.compiled-status', + { modelName: 'm', projectName: 'b' }, + ctx, + ); expect(calls).toEqual([ { type: 'dbt-check-compiled-status', @@ -139,7 +145,9 @@ describe('operationRegistry — dispatch + capabilities', () => { operations: Array<{ name: string; sideEffect: string }>; }; const names = result.operations.map((o) => o.name); - expect(names).toEqual(expect.arrayContaining(['dbt.models', 'trino.columns', 'model.create'])); + expect(names).toEqual( + expect.arrayContaining(['dbt.models', 'trino.columns', 'model.create']), + ); expect(result.operations.length).toBe(Object.keys(reg).length); }); @@ -178,7 +186,9 @@ describe('operationRegistry — dispatch + capabilities', () => { )) as { ok: boolean }; expect(res.ok).toBe(true); expect(calls[0].type).toBe('framework-model-create'); - expect((calls[0].request as { projectName: string }).projectName).toBe('analytics'); + expect((calls[0].request as { projectName: string }).projectName).toBe( + 'analytics', + ); }); }); @@ -192,7 +202,11 @@ describe('operationRegistry — authoring tier', () => { it('registers authoring read ops with sideEffect read', () => { const reg = createOperationRegistry(); - for (const name of ['model.preview', 'model.exists', 'model.cte-analysis']) { + for (const name of [ + 'model.preview', + 'model.exists', + 'model.cte-analysis', + ]) { expect(reg[name].sideEffect).toBe('read'); } }); @@ -236,9 +250,9 @@ describe('operationRegistry — authoring tier', () => { ctx, ); expect(calls[0].type).toBe('framework-model-preview'); - expect((calls[0].request as { modelJson: { name: string } }).modelJson.name).toBe( - 'customers', - ); + expect( + (calls[0].request as { modelJson: { name: string } }).modelJson.name, + ).toBe('customers'); }); it('model.preview auto-wraps flat create-style payload', async () => { @@ -265,12 +279,17 @@ describe('operationRegistry — authoring tier', () => { const reg = createOperationRegistry(); const { ctx } = makeCtx(['analytics']); await expect( - dispatch(reg, 'model.exists', { - type: 'int_select_model', - group: 'ibp', - topic: 'savings_tracker', - name: 'program_savings_monthly', - }, ctx), + dispatch( + reg, + 'model.exists', + { + type: 'int_select_model', + group: 'ibp', + topic: 'savings_tracker', + name: 'program_savings_monthly', + }, + ctx, + ), ).rejects.toThrow(/modelJson/); }); @@ -300,15 +319,20 @@ describe('operationRegistry — authoring tier', () => { const reg = createOperationRegistry(); const { ctx } = makeCtx(['analytics']); await expect( - dispatch(reg, 'model.update', { - type: 'int_select_model', - group: 'ibp', - topic: 'savings_tracker', - name: 'tenant_cost_monthly_review', - modelName: 'int__ibp__savings_tracker__tenant_cost_monthly_review', - from: { model: 'stg__x' }, - select: ['id'], - }, ctx), + dispatch( + reg, + 'model.update', + { + type: 'int_select_model', + group: 'ibp', + topic: 'savings_tracker', + name: 'tenant_cost_monthly_review', + modelName: 'int__ibp__savings_tracker__tenant_cost_monthly_review', + from: { model: 'stg__x' }, + select: ['id'], + }, + ctx, + ), ).rejects.toThrow(/originalModelPath/); }); @@ -325,7 +349,8 @@ describe('operationRegistry — authoring tier', () => { reg, 'model.update', { - originalModelPath: '/tmp/int__ibp__savings_tracker__tenant_cost_monthly_review.model.json', + originalModelPath: + '/tmp/int__ibp__savings_tracker__tenant_cost_monthly_review.model.json', modelJson, }, ctx, @@ -343,7 +368,12 @@ describe('operationRegistry — authoring tier', () => { describe('operationRegistry — mutate tier', () => { it('registers dbt mutate ops as mutate', () => { const reg = createOperationRegistry(); - for (const name of ['dbt.compile', 'dbt.compile-logs', 'dbt.parse', 'dbt.run']) { + for (const name of [ + 'dbt.compile', + 'dbt.compile-logs', + 'dbt.parse', + 'dbt.run', + ]) { expect(reg[name].sideEffect).toBe('mutate'); } }); @@ -422,7 +452,12 @@ describe('operationRegistry — query & data read tier', () => { it('model.reverse-lineage forwards the flat { kind, slug } payload', async () => { const reg = createOperationRegistry(); const { ctx, calls } = makeCtx(); - await dispatch(reg, 'model.reverse-lineage', { kind: 'chart', slug: 's' }, ctx); + await dispatch( + reg, + 'model.reverse-lineage', + { kind: 'chart', slug: 's' }, + ctx, + ); expect(calls).toEqual([ { type: 'data-explorer-get-reverse-lineage', @@ -446,7 +481,12 @@ describe('operationRegistry — query & data read tier', () => { it('query.execute allows WITH / SHOW / a leading comment', async () => { const reg = createOperationRegistry(); const { ctx, calls } = makeCtx(); - await dispatch(reg, 'query.execute', { sql: 'with t as (select 1) select * from t' }, ctx); + await dispatch( + reg, + 'query.execute', + { sql: 'with t as (select 1) select * from t' }, + ctx, + ); await dispatch(reg, 'query.execute', { sql: 'SHOW TABLES' }, ctx); await dispatch(reg, 'query.execute', { sql: '-- note\nselect 1' }, ctx); expect(calls).toHaveLength(3); @@ -480,7 +520,12 @@ describe('operationRegistry — query & data read tier', () => { const reg = createOperationRegistry(); const { ctx } = makeCtx(); await expect( - dispatch(reg, 'query.execute', { sql: '/* select */ delete from t' }, ctx), + dispatch( + reg, + 'query.execute', + { sql: '/* select */ delete from t' }, + ctx, + ), ).rejects.toThrow(/read-only SELECT/); }); }); diff --git a/src/services/cliBridge/__tests__/requestShape.test.ts b/src/services/cliBridge/__tests__/requestShape.test.ts index 25e9b76..3be9b20 100644 --- a/src/services/cliBridge/__tests__/requestShape.test.ts +++ b/src/services/cliBridge/__tests__/requestShape.test.ts @@ -20,7 +20,12 @@ describe('requestShape', () => { it('assertModelExistsPayload requires identity fields on modelJson', () => { expect(() => assertModelExistsPayload({ - modelJson: { type: 'stg_select_source', group: 'g', topic: 't', name: 'n' }, + modelJson: { + type: 'stg_select_source', + group: 'g', + topic: 't', + name: 'n', + }, }), ).not.toThrow(); expect(() => diff --git a/src/services/cliBridge/operationRegistry.ts b/src/services/cliBridge/operationRegistry.ts index 2ed1535..965a385 100644 --- a/src/services/cliBridge/operationRegistry.ts +++ b/src/services/cliBridge/operationRegistry.ts @@ -16,17 +16,17 @@ import { normalizeDbtCompileRequest, normalizeWrappedModelRequest, } from '@services/cliBridge/requestShape'; +import { + formatGlobalHelp, + formatOperationHelpSummary, + listOperationHelp, +} from '@shared/cli/operationHelp'; import type { OperationContext, OperationDef, OperationRegistry, SideEffect, } from '@shared/cli/types'; -import { - formatGlobalHelp, - formatOperationHelpSummary, - listOperationHelp, -} from '@shared/cli/operationHelp'; /** * Normalize a CLI input payload into the `request` object `handleApi` expects. @@ -567,7 +567,7 @@ export function createOperationRegistry(): OperationRegistry { register({ name: 'model.lineage', description: - "Get upstream/downstream lineage. CLI defaults depth to -1 (walk to sources) unless overridden. Optional maxNodes (default 50). Requires { modelName }; projectName optional when a single dbt project exists.", + 'Get upstream/downstream lineage. CLI defaults depth to -1 (walk to sources) unless overridden. Optional maxNodes (default 50). Requires { modelName }; projectName optional when a single dbt project exists.', sideEffect: 'read', handler: async (input, ctx) => { const request = readRequest(input, { allowEmpty: true }) as Record< @@ -637,7 +637,7 @@ export function createOperationRegistry(): OperationRegistry { handler: async (input, ctx) => { const request = readRequest(input, { allowEmpty: true, - }) as Record | null; + }); assertQueryExecutePayload(request); const sql = request!.sql as string; assertReadOnlySelect(sql); diff --git a/src/services/cliBridge/requestShape.ts b/src/services/cliBridge/requestShape.ts index fd2cf7c..16394da 100644 --- a/src/services/cliBridge/requestShape.ts +++ b/src/services/cliBridge/requestShape.ts @@ -71,20 +71,14 @@ export function assertWrappedModelJsonPayload( export function normalizeWrappedModelRequest( request: Record, ): Record { - if ( - !('modelJson' in request) && - looksLikeFlatModelCreatePayload(request) - ) { + if (!('modelJson' in request) && looksLikeFlatModelCreatePayload(request)) { const { projectName, ...modelFields } = request; return { ...(typeof projectName === 'string' ? { projectName } : {}), modelJson: modelFields, }; } - if ( - !('modelJson' in request) && - looksLikeRawModelJsonBody(request) - ) { + if (!('modelJson' in request) && looksLikeRawModelJsonBody(request)) { const { projectName, ...modelFields } = request; return { ...(typeof projectName === 'string' ? { projectName } : {}), @@ -118,8 +112,7 @@ export function assertModelUpdatePayload( ); } const path = request.originalModelPath; - const hasPath = - typeof path === 'string' && path.trim() !== ''; + const hasPath = typeof path === 'string' && path.trim() !== ''; const hasModelJson = isPlainObject(request.modelJson); const hasModelName = typeof request.modelName === 'string' && request.modelName.trim() !== ''; @@ -133,7 +126,10 @@ export function assertModelUpdatePayload( ) { hint = ' Use "originalModelPath" (absolute path to the .model.json) or "modelName" (resolved within projectName) plus "modelJson".'; - } else if (looksLikeRawModelJsonBody(request) || looksLikeFlatModelCreatePayload(request)) { + } else if ( + looksLikeRawModelJsonBody(request) || + looksLikeFlatModelCreatePayload(request) + ) { hint = ' Do not pass a raw .model.json file as the whole payload; use { "originalModelPath": "", "modelJson": { … } }.'; } @@ -212,11 +208,7 @@ export function normalizeDbtCompileRequest( delete working.modelNames; } - const allowedAfterNormalize = new Set([ - 'projectName', - 'modelName', - 'select', - ]); + const allowedAfterNormalize = new Set(['projectName', 'modelName', 'select']); const unknown = Object.keys(working).filter( (k) => !allowedAfterNormalize.has(k), ); @@ -242,8 +234,7 @@ export function normalizeDbtCompileRequest( } const projectName = - typeof working.projectName === 'string' && - working.projectName.trim() !== '' + typeof working.projectName === 'string' && working.projectName.trim() !== '' ? working.projectName.trim() : undefined; diff --git a/src/services/framework/__tests__/index.test.ts b/src/services/framework/__tests__/index.test.ts index 5567a53..1f5b9ca 100644 --- a/src/services/framework/__tests__/index.test.ts +++ b/src/services/framework/__tests__/index.test.ts @@ -618,6 +618,49 @@ describe('materialization shorthand', () => { expect(config.materialized).toBe('incremental'); expect(config.incremental_strategy).toBe('delete+insert'); + expect(config.pre_hook).toContain('iterative_optimizer_timeout'); + }); + + test('sql_hooks.pre null omits the incremental session pre-hook', () => { + const modelJson: FrameworkModel = { + type: 'int_select_model', + group: 'sales', + topic: 'orders', + name: 'enriched', + materialization: 'incremental', + sql_hooks: { pre: null }, + select: [{ model: 'model_a', columns: ['dim_a'] }], + from: { model: 'model_a' }, + } as unknown as FrameworkModel; + + const { config } = frameworkGenerateModelOutput({ + dj: { config: {} }, + modelJson, + project, + }); + + expect(config.pre_hook).toBeUndefined(); + }); + + test('an authored sql_hooks.pre replaces the session pre-hook', () => { + const modelJson: FrameworkModel = { + type: 'int_select_model', + group: 'sales', + topic: 'orders', + name: 'enriched', + materialization: 'incremental', + sql_hooks: { pre: 'select 1' }, + select: [{ model: 'model_a', columns: ['dim_a'] }], + from: { model: 'model_a' }, + } as unknown as FrameworkModel; + + const { config } = frameworkGenerateModelOutput({ + dj: { config: {} }, + modelJson, + project, + }); + + expect(config.pre_hook).toBe('select 1'); }); test('"materialization": "incremental" respects config override to merge', () => { diff --git a/src/services/framework/__tests__/make-model-template.test.ts b/src/services/framework/__tests__/make-model-template.test.ts new file mode 100644 index 0000000..ce2fdf5 --- /dev/null +++ b/src/services/framework/__tests__/make-model-template.test.ts @@ -0,0 +1,43 @@ +import { describe, expect, test } from '@jest/globals'; +import { frameworkMakeModelTemplate } from '@services/framework/utils/sql-utils'; + +describe('frameworkMakeModelTemplate materialization', () => { + test('emits materialization shorthand instead of deprecated materialized', () => { + const model = frameworkMakeModelTemplate({ + projectName: 'p', + type: 'int_select_model', + group: 'g', + topic: 't', + name: 'n', + materialized: 'ephemeral', + from: { model: 'stg__x' }, + select: [], + }); + + expect(model).toMatchObject({ materialization: 'ephemeral' }); + expect(model).not.toHaveProperty('materialized'); + }); + + test('folds legacy incremental_strategy and partitioned_by into materialization', () => { + const model = frameworkMakeModelTemplate({ + projectName: 'p', + type: 'int_select_model', + group: 'g', + topic: 't', + name: 'n', + materialized: 'incremental', + incremental_strategy: { type: 'append' }, + partitioned_by: ['portal_partition_daily'], + from: { model: 'stg__x' }, + select: [], + }); + + expect((model as { materialization?: unknown }).materialization).toEqual({ + type: 'incremental', + strategy: { type: 'append' }, + partitions: ['portal_partition_daily'], + }); + expect(model).not.toHaveProperty('incremental_strategy'); + expect(model).not.toHaveProperty('partitioned_by'); + }); +}); diff --git a/src/services/framework/handlers/model-crud-handlers.ts b/src/services/framework/handlers/model-crud-handlers.ts index 5a631bc..665b4df 100644 --- a/src/services/framework/handlers/model-crud-handlers.ts +++ b/src/services/framework/handlers/model-crud-handlers.ts @@ -21,6 +21,7 @@ import { jsonParse, removeEmpty } from '@shared'; import type { ApiPayload, ApiResponse } from '@shared/api/types'; import { apiResponse } from '@shared/api/utils'; import type { DbtProject } from '@shared/dbt/types'; +import { materializationInsertionIndex } from '@shared/framework/materialization'; import type { FrameworkColumn, FrameworkModel, @@ -117,7 +118,9 @@ export class ModelCrudHandlers { private prepareModelJsonFromRequest( request: Record, - autoGenerateTestsConfig: ReturnType['autoGenerateTests'], + autoGenerateTestsConfig: ReturnType< + typeof getDjConfig + >['autoGenerateTests'], ): FrameworkModel { const templated = frameworkMakeModelTemplate( request as Parameters[0], @@ -255,7 +258,13 @@ export class ModelCrudHandlers { throw new Error('model.create-batch requires a non-empty models array'); } - const written: Array<{ modelPath: string; modelName: string; fileInfo: Awaited> }> = []; + const written: Array<{ + modelPath: string; + modelName: string; + fileInfo: Awaited< + ReturnType + >; + }> = []; for (const raw of models) { const modelJson = this.prepareModelJsonFromRequest( @@ -303,7 +312,9 @@ export class ModelCrudHandlers { } catch (err: unknown) { synced = false; batchSyncErrors = [ - err instanceof Error ? err.message : 'Unknown sync error after batch create', + err instanceof Error + ? err.message + : 'Unknown sync error after batch create', ]; } } @@ -589,8 +600,19 @@ export class ModelCrudHandlers { if (isEqual(existingValue, value)) { continue; } + const existingRecord = existingModelJson as unknown as Record< + string, + unknown + >; + const replaceMaterialized = + key === 'materialization' && + 'materialized' in existingRecord && + !('materialization' in existingRecord); const edits = modify(updatedContent, [key], value, { formattingOptions: JSONC_FORMAT_OPTIONS, + ...(replaceMaterialized && { + getInsertionIndex: materializationInsertionIndex, + }), }); updatedContent = applyEdits(updatedContent, edits); } diff --git a/src/services/framework/handlers/model-data-handlers.ts b/src/services/framework/handlers/model-data-handlers.ts index 715f0be..13aaafe 100644 --- a/src/services/framework/handlers/model-data-handlers.ts +++ b/src/services/framework/handlers/model-data-handlers.ts @@ -14,13 +14,13 @@ import { } from '@services/framework/utils'; import type { ApiPayload, ApiResponse } from '@shared/api/types'; import { apiResponse } from '@shared/api/utils'; -import { getDbtModelId } from '@shared/dbt/utils'; import { buildModelSummariesForProject, rankSimilarModels, } from '@shared/dbt/modelCatalogSearch'; -import type { FrameworkModel } from '@shared/framework/types'; +import { getDbtModelId } from '@shared/dbt/utils'; import { buildDataCheckSql } from '@shared/framework/dataCheckTemplates'; +import type { FrameworkModel } from '@shared/framework/types'; import * as fs from 'fs'; import * as path from 'path'; import * as vscode from 'vscode'; @@ -285,15 +285,8 @@ export class ModelDataHandlers { handleModelSimilar( payload: ApiPayload<'framework'> & { type: 'framework-model-similar' }, ): ApiResponse { - const { - projectName, - modelName, - fromModel, - group, - topic, - tags, - limit, - } = payload.request; + const { projectName, modelName, fromModel, group, topic, tags, limit } = + payload.request; const project = this.ctx.dbt.projects.get(projectName); if (!project) { throw new Error(`Project ${projectName} not found`); diff --git a/src/services/framework/utils/resolve-model-json-path.ts b/src/services/framework/utils/resolve-model-json-path.ts index de0932e..1b226f2 100644 --- a/src/services/framework/utils/resolve-model-json-path.ts +++ b/src/services/framework/utils/resolve-model-json-path.ts @@ -25,7 +25,10 @@ export async function resolveModelJsonPath({ if (modelId) { const model = dbt.models.get(modelId); if (model?.pathSystemFile) { - const fromManifest = model.pathSystemFile.replace(/\.sql$/, '.model.json'); + const fromManifest = model.pathSystemFile.replace( + /\.sql$/, + '.model.json', + ); if (fs.existsSync(fromManifest)) { return fromManifest; } @@ -50,7 +53,10 @@ export async function resolveModelJsonPath({ ); } - const flatCandidate = path.join(project.pathSystem, `${modelName}.model.json`); + const flatCandidate = path.join( + project.pathSystem, + `${modelName}.model.json`, + ); if (fs.existsSync(flatCandidate)) { return flatCandidate; } diff --git a/src/services/framework/utils/sql-utils.ts b/src/services/framework/utils/sql-utils.ts index 63e3052..0e5129e 100644 --- a/src/services/framework/utils/sql-utils.ts +++ b/src/services/framework/utils/sql-utils.ts @@ -36,6 +36,7 @@ import { getDbtModelId } from '@shared/dbt/utils'; import { BULK_CTE_TYPES, BULK_MODEL_TYPES, + DEFAULT_INCREMENTAL_PRE_HOOK, DEFAULT_INCREMENTAL_STRATEGY, FRAMEWORK_PARTITIONS, JOIN_ON_DIMS, @@ -44,6 +45,7 @@ import { PARTITION_HOURLY, PARTITION_MONTHLY, } from '@shared/framework/constants'; +import { normalizeMaterializationFromLegacyRequest } from '@shared/framework/materialization'; import type { FrameworkColumn, FrameworkColumnAgg, @@ -2290,9 +2292,10 @@ export function frameworkGenerateModelOutput({ } } - // Trino session settings for long-running incremental queries - modelConfig.pre_hook = - "set session iterative_optimizer_timeout='60m'; set session query_max_planning_time='60m'"; + // Trino session settings for long-running incremental queries. + // Omitted `sql_hooks.pre` keeps this hook. `null` removes it. + // A string or array below replaces it. + modelConfig.pre_hook = DEFAULT_INCREMENTAL_PRE_HOOK; // Resolve storage format (model `format` > project `storage_type`). // Iceberg expresses bucketing as a `bucket(col,n)` transform inside @@ -2367,7 +2370,9 @@ export function frameworkGenerateModelOutput({ if (modelJson.sql_hooks.post) { modelConfig.post_hook = modelJson.sql_hooks.post; } - if (modelJson.sql_hooks.pre) { + if (modelJson.sql_hooks.pre === null) { + delete modelConfig.pre_hook; + } else if (modelJson.sql_hooks.pre) { modelConfig.pre_hook = modelJson.sql_hooks.pre; } } @@ -3206,13 +3211,16 @@ export function frameworkModelNodeColor({ * @see utils.ts:2091-2733 */ export function frameworkMakeModelTemplate( - { + request: Api<'framework-model-create'>['request'], + autoGenerateTestsConfig: AutoGenerateTestsConfig = { + tests: { equalRowCount: { enabled: true, applyTo: ['left'] } }, + }, +): FrameworkModel { + const { type, group, name, topic, - materialized, - materialization, from, select, group_by, @@ -3220,9 +3228,7 @@ export function frameworkMakeModelTemplate( lightdash, description, tags, - incremental_strategy, sql_hooks, - partitioned_by, exclude_daily_filter, exclude_date_filter, exclude_datetime, @@ -3230,11 +3236,19 @@ export function frameworkMakeModelTemplate( exclude_portal_partition_columns, exclude_portal_source_count, ctes, - }: Api<'framework-model-create'>['request'], - autoGenerateTestsConfig: AutoGenerateTestsConfig = { - tests: { equalRowCount: { enabled: true, applyTo: ['left'] } }, - }, -): FrameworkModel { + materialized, + materialization, + incremental_strategy, + partitioned_by, + } = request; + + const normalizedMaterialization = normalizeMaterializationFromLegacyRequest({ + materialized, + materialization, + incremental_strategy, + partitioned_by, + }); + /** * Build base model object with required and optional fields * These fields are common across all model types @@ -3246,28 +3260,18 @@ export function frameworkMakeModelTemplate( name, // Optional basic fields - ...(materialized && { materialized }), - ...(materialization !== undefined && { materialization }), + ...(normalizedMaterialization && { + materialization: normalizedMaterialization, + }), ...(description && { description }), ...(tags && tags.length > 0 && { tags }), - // Incremental strategy configuration - ...(incremental_strategy && { - incremental_strategy: incremental_strategy as any, - }), - // SQL hooks configuration ...(sql_hooks && - (sql_hooks.pre || sql_hooks.post) && { + (sql_hooks.pre !== undefined || sql_hooks.post) && { sql_hooks: sql_hooks as any, }), - // Partitioning configuration - ...(partitioned_by && - partitioned_by.length > 0 && { - partitioned_by: partitioned_by as any, - }), - // Exclude filter flags ...(exclude_daily_filter !== undefined && { exclude_daily_filter }), ...(exclude_date_filter !== undefined && { exclude_date_filter }), diff --git a/src/services/modelLineage.ts b/src/services/modelLineage.ts index e01f5e3..0ab3243 100644 --- a/src/services/modelLineage.ts +++ b/src/services/modelLineage.ts @@ -39,12 +39,7 @@ export class ModelLineage { switch (payload.type) { case 'data-explorer-get-model-lineage': { try { - const { - modelName, - projectName, - depth, - maxNodes, - } = payload.request; + const { modelName, projectName, depth, maxNodes } = payload.request; this.coder.log.info( `Fetching lineage for model: ${modelName} in project: ${projectName}`, ); @@ -1053,7 +1048,11 @@ export class ModelLineage { `[executeModelQuery] Using compiled SQL from: ${compiledPath}`, ); - const schemaColumns = this.getSchemaColumnNames(project, modelName, projectName); + const schemaColumns = this.getSchemaColumnNames( + project, + modelName, + projectName, + ); let queryWithLimit = compiledSql.trim(); if (opts.aggregations) { @@ -1086,7 +1085,7 @@ export class ModelLineage { }; } - let columns = Object.keys(rawResults[0]); + const columns = Object.keys(rawResults[0]); const rows = rawResults.map((row) => columns.map((col) => row[col])); return { columns, schemaColumns, rows, rowCount: rows.length }; } diff --git a/src/services/modelValidation.ts b/src/services/modelValidation.ts index da6aeb2..74ac7e4 100644 --- a/src/services/modelValidation.ts +++ b/src/services/modelValidation.ts @@ -2193,11 +2193,14 @@ const VALID_ROLLUP_INTERVALS = new Set([ ]); /** Rejects rollup intervals outside the JSON schema enum (e.g. `week`). */ -export function validateRollupInterval(modelJson: unknown): ValidationErrorDetail[] { +export function validateRollupInterval( + modelJson: unknown, +): ValidationErrorDetail[] { if (!modelJson || typeof modelJson !== 'object') { return []; } - const from = (modelJson as { from?: { rollup?: { interval?: string } } }).from; + const from = (modelJson as { from?: { rollup?: { interval?: string } } }) + .from; const interval = from?.rollup?.interval; if (typeof interval !== 'string') { return []; diff --git a/src/services/modeling/providers/DbtModelingFrameworkProvider.ts b/src/services/modeling/providers/DbtModelingFrameworkProvider.ts index 691b75c..1523bdb 100644 --- a/src/services/modeling/providers/DbtModelingFrameworkProvider.ts +++ b/src/services/modeling/providers/DbtModelingFrameworkProvider.ts @@ -13,9 +13,7 @@ export class DbtModelingFrameworkProvider implements ModelingFrameworkProvider { warn: (...args: unknown[]) => void; }; - constructor(options?: { - logger?: { warn: (...args: unknown[]) => void }; - }) { + constructor(options?: { logger?: { warn: (...args: unknown[]) => void } }) { this.logger = options?.logger; } diff --git a/src/shared/cli/__tests__/operationHelp.test.ts b/src/shared/cli/__tests__/operationHelp.test.ts index d7e9ec5..dc9c364 100644 --- a/src/shared/cli/__tests__/operationHelp.test.ts +++ b/src/shared/cli/__tests__/operationHelp.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, it } from '@jest/globals'; +import { createOperationRegistry } from '@services/cliBridge/operationRegistry'; import { CLI_OPERATION_NAMES, formatGlobalHelp, @@ -5,12 +7,13 @@ import { getOperationHelp, listOperationHelp, } from '@shared/cli/operationHelp'; -import { createOperationRegistry } from '@services/cliBridge/operationRegistry'; describe('operationHelp', () => { it('lists help for every bridge op except system.help', () => { const registry = createOperationRegistry(); - const registryNames = Object.keys(registry).filter((n) => n !== 'system.help'); + const registryNames = Object.keys(registry).filter( + (n) => n !== 'system.help', + ); expect(registryNames.sort()).toEqual([...CLI_OPERATION_NAMES].sort()); for (const name of registryNames) { expect(getOperationHelp(name)).toBeDefined(); diff --git a/src/shared/cli/mergePayload.ts b/src/shared/cli/mergePayload.ts index bdae950..5ee4668 100644 --- a/src/shared/cli/mergePayload.ts +++ b/src/shared/cli/mergePayload.ts @@ -28,7 +28,7 @@ export function mergeCliPayload( base = {}; } else if (isPlainObject(input)) { if ('request' in input && isPlainObject(input.request)) { - base = { ...(input.request as Record) }; + base = { ...input.request }; } else { base = { ...input }; } diff --git a/src/shared/cli/operationHelp.ts b/src/shared/cli/operationHelp.ts index abd02ac..193e346 100644 --- a/src/shared/cli/operationHelp.ts +++ b/src/shared/cli/operationHelp.ts @@ -22,20 +22,11 @@ export type OperationHelp = { defaultTimeoutMs?: number; }; -const COMMON_FLAGS = [ - '--file', - '--json', - '--workspace', - '--timeout', -] as const; +const COMMON_FLAGS = ['--file', '--json', '--workspace', '--timeout'] as const; const PROJECT_FLAGS = [...COMMON_FLAGS, '--projectName'] as const; -const MODEL_NAME_FLAGS = [ - ...PROJECT_FLAGS, - '--modelName', - '--depth', -] as const; +const MODEL_NAME_FLAGS = [...PROJECT_FLAGS, '--modelName', '--depth'] as const; function help(entry: OperationHelp): OperationHelp { return entry; @@ -127,7 +118,8 @@ const HELP_BY_NAME: Record = { }), 'dbt.models.search': help({ operation: 'dbt.models.search', - description: 'Search models by pattern, topic, group, tags, fromModel, etc.', + description: + 'Search models by pattern, topic, group, tags, fromModel, etc.', sideEffect: 'read', payloadRequired: 'optional', preferredInvoke: 'fileAndFlags', @@ -312,7 +304,8 @@ const HELP_BY_NAME: Record = { }), 'model.update': help({ operation: 'model.update', - description: 'Update an existing model (merge, validate, relocate on rename).', + description: + 'Update an existing model (merge, validate, relocate on rename).', sideEffect: 'mutate', payloadRequired: 'required', preferredInvoke: 'fileWrappedModelJson', diff --git a/src/shared/dbt/modelCatalogSearch.ts b/src/shared/dbt/modelCatalogSearch.ts index d524ca6..02b97b2 100644 --- a/src/shared/dbt/modelCatalogSearch.ts +++ b/src/shared/dbt/modelCatalogSearch.ts @@ -125,10 +125,7 @@ export function matchesModelSearchFilters( if (filters.fromModel && summary.fromModel !== filters.fromModel) { return false; } - if ( - filters.requireLightdashExploreTag && - !summary.hasLightdashExplore - ) { + if (filters.requireLightdashExploreTag && !summary.hasLightdashExplore) { return false; } if (filters.tags?.length) { @@ -140,8 +137,10 @@ export function matchesModelSearchFilters( if ( filters.pattern && !matchesPattern(summary.name, filters.pattern) && - !(summary.lightdashTableLabel && - matchesPattern(summary.lightdashTableLabel, filters.pattern)) + !( + summary.lightdashTableLabel && + matchesPattern(summary.lightdashTableLabel, filters.pattern) + ) ) { return false; } @@ -206,8 +205,6 @@ export function rankSimilarModels( } } - scored.sort( - (a, b) => b.score - a.score || a.name.localeCompare(b.name), - ); + scored.sort((a, b) => b.score - a.score || a.name.localeCompare(b.name)); return scored.slice(0, limit); } diff --git a/src/shared/dbt/types.ts b/src/shared/dbt/types.ts index 7b69bb8..986d59a 100644 --- a/src/shared/dbt/types.ts +++ b/src/shared/dbt/types.ts @@ -34,7 +34,7 @@ export type DbtApi = request: null; response: string[]; } - | { + | { type: 'dbt-fetch-available-models'; service: 'dbt'; request: { diff --git a/src/shared/framework/__tests__/materialization.test.ts b/src/shared/framework/__tests__/materialization.test.ts new file mode 100644 index 0000000..5d35ac5 --- /dev/null +++ b/src/shared/framework/__tests__/materialization.test.ts @@ -0,0 +1,110 @@ +import { describe, expect, test } from '@jest/globals'; +import { + buildMaterializationForWizardOutput, + getIncrementalStrategy, + getMaterializationType, + getPartitions, + materializationInsertionIndex, + normalizeMaterializationFromLegacyRequest, + pickMaterializationExtras, +} from '@shared/framework/materialization'; + +describe('materialization helpers', () => { + test('getMaterializationType resolves legacy and nested shapes', () => { + expect(getMaterializationType({ materialized: 'ephemeral' })).toBe( + 'ephemeral', + ); + expect(getMaterializationType({ materialization: 'incremental' })).toBe( + 'incremental', + ); + expect( + getMaterializationType({ + materialization: { type: 'incremental', strategy: { type: 'append' } }, + }), + ).toBe('incremental'); + }); + + test('getIncrementalStrategy prefers nested strategy', () => { + expect( + getIncrementalStrategy({ + materialization: { + type: 'incremental', + strategy: { type: 'merge', unique_key: 'id' }, + }, + incremental_strategy: { type: 'append' }, + }), + ).toEqual({ type: 'merge', unique_key: 'id' }); + expect( + getIncrementalStrategy({ + incremental_strategy: { type: 'delete+insert' }, + }), + ).toEqual({ type: 'delete+insert' }); + }); + + test('getPartitions prefers nested partitions', () => { + expect( + getPartitions({ + materialization: { + type: 'incremental', + partitions: ['portal_partition_daily'], + }, + partitioned_by: ['other'], + }), + ).toEqual(['portal_partition_daily']); + }); + + test('pickMaterializationExtras copies wizard-non-owned keys', () => { + expect( + pickMaterializationExtras({ + type: 'incremental', + format: 'iceberg', + strategy: { type: 'append' }, + partitions: ['x'], + }), + ).toEqual({ format: 'iceberg' }); + }); + + test('buildMaterializationForWizardOutput uses string shorthand when minimal', () => { + expect(buildMaterializationForWizardOutput({ type: 'ephemeral' })).toBe( + 'ephemeral', + ); + expect(buildMaterializationForWizardOutput({ type: 'incremental' })).toBe( + 'incremental', + ); + }); + + test('buildMaterializationForWizardOutput uses object when strategy or partitions set', () => { + expect( + buildMaterializationForWizardOutput({ + type: 'incremental', + strategy: { type: 'delete+insert' }, + partitions: ['portal_partition_daily'], + }), + ).toEqual({ + type: 'incremental', + strategy: { type: 'delete+insert' }, + partitions: ['portal_partition_daily'], + }); + }); + + test('normalizeMaterializationFromLegacyRequest folds flat fields', () => { + expect( + normalizeMaterializationFromLegacyRequest({ + materialized: 'incremental', + incremental_strategy: { type: 'append' }, + partitioned_by: ['portal_partition_daily'], + }), + ).toEqual({ + type: 'incremental', + strategy: { type: 'append' }, + partitions: ['portal_partition_daily'], + }); + }); + + test('materializationInsertionIndex uses the legacy materialized slot', () => { + expect( + materializationInsertionIndex(['type', 'name', 'materialized', 'from']), + ).toBe(2); + expect(materializationInsertionIndex(['type', 'name'])).toBe(2); + }); +}); diff --git a/src/shared/framework/constants.ts b/src/shared/framework/constants.ts index 58b39b9..11b1342 100644 --- a/src/shared/framework/constants.ts +++ b/src/shared/framework/constants.ts @@ -22,6 +22,13 @@ import type { export const DEFAULT_INCREMENTAL_STRATEGY: DefaultIncrementalStrategy = 'overwrite_existing_partitions'; +/** + * Session pre-hook DJ adds for incremental models when `sql_hooks.pre` is + * omitted. `sql_hooks.pre: null` disables it. A string or array replaces it. + */ +export const DEFAULT_INCREMENTAL_PRE_HOOK = + "set session iterative_optimizer_timeout='60m'; set session query_max_planning_time='60m'"; + // Named constants for the framework-injected partition column names, used // throughout SQL generation, column building, and filter logic. They live in // the shared barrel so the extension backend and the webview resolve a single diff --git a/src/shared/framework/dataCheckTemplates.ts b/src/shared/framework/dataCheckTemplates.ts index 6a6894b..4e48324 100644 --- a/src/shared/framework/dataCheckTemplates.ts +++ b/src/shared/framework/dataCheckTemplates.ts @@ -28,7 +28,9 @@ LIMIT ${limit}`, } case 'utilization_band': { const relation = - typeof params.relation === 'string' ? params.relation : 'compiled_model_subquery'; + typeof params.relation === 'string' + ? params.relation + : 'compiled_model_subquery'; const limit = Number(params.limit ?? 100); return { description: 'Utilization percentage band check (0–100%).', @@ -41,7 +43,9 @@ LIMIT ${limit}`, } case 'recent_partition_window': { const relation = - typeof params.relation === 'string' ? params.relation : 'compiled_model_subquery'; + typeof params.relation === 'string' + ? params.relation + : 'compiled_model_subquery'; const days = Number(params.days ?? 7); const limit = Number(params.limit ?? 500); return { diff --git a/src/shared/framework/materialization.ts b/src/shared/framework/materialization.ts new file mode 100644 index 0000000..4a3b22c --- /dev/null +++ b/src/shared/framework/materialization.ts @@ -0,0 +1,211 @@ +import type { + IncrementalStrategy, + SchemaModelMaterialization, +} from '@shared/schema/types/model.materialization.schema'; +import type { SchemaModelMaterialized } from '@shared/schema/types/model.materialized.schema'; +import type { SchemaModelPartitionedBy } from '@shared/schema/types/model.partitioned_by.schema'; + +export type MaterializationTypeShorthand = SchemaModelMaterialized; + +export const DEPRECATED_MATERIALIZATION_TOP_LEVEL_KEYS = [ + 'materialized', + 'incremental_strategy', + 'partitioned_by', +] as const; + +export type MaterializationExtras = Partial< + Pick< + Extract, + 'format' | 'database' | 'bucket' | 'sorted_by' + > +>; + +type MaterializationInput = { + materialized?: MaterializationTypeShorthand; + materialization?: SchemaModelMaterialization; + incremental_strategy?: IncrementalStrategy; + partitioned_by?: SchemaModelPartitionedBy; +}; + +export function getMaterializationType( + model: MaterializationInput, +): MaterializationTypeShorthand | undefined { + if (model.materialized) { + return model.materialized; + } + const mat = model.materialization; + if (!mat) { + return undefined; + } + if (typeof mat === 'string') { + return mat; + } + if (mat.type === 'incremental' || mat.type === 'ephemeral') { + return mat.type; + } + return undefined; +} + +export function getIncrementalStrategy( + model: MaterializationInput, +): IncrementalStrategy | undefined { + const mat = model.materialization; + if (mat && typeof mat === 'object' && mat.type === 'incremental') { + return mat.strategy; + } + return model.incremental_strategy; +} + +export function getPartitions( + model: MaterializationInput, +): SchemaModelPartitionedBy | undefined { + const mat = model.materialization; + if (mat && typeof mat === 'object' && mat.type === 'incremental') { + return mat.partitions as SchemaModelPartitionedBy | undefined; + } + return model.partitioned_by; +} + +export function pickMaterializationExtras( + materialization: SchemaModelMaterialization | undefined, +): MaterializationExtras { + if (!materialization || typeof materialization !== 'object') { + return {}; + } + if (materialization.type !== 'incremental') { + return {}; + } + const extras: MaterializationExtras = {}; + if (materialization.format !== undefined) { + extras.format = materialization.format; + } + if (materialization.database !== undefined) { + extras.database = materialization.database; + } + if (materialization.bucket !== undefined) { + extras.bucket = materialization.bucket; + } + if (materialization.sorted_by !== undefined) { + extras.sorted_by = materialization.sorted_by; + } + return extras; +} + +function hasMaterializationExtras(extras: MaterializationExtras): boolean { + return Object.keys(extras).length > 0; +} + +function hasStrategy(strategy: IncrementalStrategy | undefined): boolean { + return strategy !== undefined && strategy !== null; +} + +function hasPartitions( + partitions: SchemaModelPartitionedBy | undefined, +): boolean { + return ( + partitions !== undefined && + Array.isArray(partitions) && + partitions.length > 0 + ); +} + +export function buildMaterializationForWizardOutput({ + type, + strategy, + partitions, + extras = {}, +}: { + type?: MaterializationTypeShorthand; + strategy?: IncrementalStrategy; + partitions?: SchemaModelPartitionedBy; + extras?: MaterializationExtras; +}): SchemaModelMaterialization | undefined { + if (!type) { + return undefined; + } + + if (type === 'ephemeral') { + if (hasMaterializationExtras(extras)) { + return { type: 'ephemeral' }; + } + return 'ephemeral'; + } + + const strategyPresent = hasStrategy(strategy); + const partitionsPresent = hasPartitions(partitions); + const extrasPresent = hasMaterializationExtras(extras); + + if (!strategyPresent && !partitionsPresent && !extrasPresent) { + return 'incremental'; + } + + const incremental: Extract< + SchemaModelMaterialization, + { type: 'incremental' } + > = { + type: 'incremental', + ...extras, + }; + if (strategyPresent) { + incremental.strategy = strategy; + } + if (partitionsPresent) { + incremental.partitions = partitions; + } + return incremental; +} + +/** + * Normalize a create/preview request that may still carry legacy top-level fields. + */ +export function normalizeMaterializationFromLegacyRequest( + request: MaterializationInput & { + type?: MaterializationTypeShorthand; + strategy?: IncrementalStrategy; + partitions?: SchemaModelPartitionedBy; + extras?: MaterializationExtras; + }, +): SchemaModelMaterialization | undefined { + if (request.materialization) { + const type = getMaterializationType(request); + if (!type) { + return request.materialization; + } + return buildMaterializationForWizardOutput({ + type, + strategy: getIncrementalStrategy(request), + partitions: getPartitions(request), + extras: { + ...pickMaterializationExtras(request.materialization), + ...request.extras, + }, + }); + } + + const type = request.type ?? getMaterializationType(request); + if (!type) { + return undefined; + } + + return buildMaterializationForWizardOutput({ + type, + strategy: request.strategy ?? getIncrementalStrategy(request), + partitions: request.partitions ?? getPartitions(request), + extras: request.extras ?? {}, + }); +} + +/** + * Index at which a new `materialization` property should be inserted when + * replacing a legacy `materialized` key. Falls back to appending. + */ +export function materializationInsertionIndex(properties: string[]): number { + const idx = properties.indexOf('materialized'); + return idx >= 0 ? idx : properties.length; +} + +export function deprecatedMaterializationNullSentinels(): Record { + return Object.fromEntries( + DEPRECATED_MATERIALIZATION_TOP_LEVEL_KEYS.map((key) => [key, null]), + ); +} diff --git a/src/shared/framework/types.ts b/src/shared/framework/types.ts index 760db89..7e70495 100644 --- a/src/shared/framework/types.ts +++ b/src/shared/framework/types.ts @@ -117,6 +117,7 @@ export type FrameworkApi = type: FrameworkModel['type']; projectName: string; validateOnly?: boolean; + /** @deprecated Legacy wizard/sync input; normalized to `materialization` in templates */ materialized?: SchemaModelMaterialized; materialization?: SchemaModelMaterialization; source?: string; // UI field, should be excluded from actual API request @@ -124,7 +125,7 @@ export type FrameworkApi = tags?: string[]; incremental_strategy?: IncrementalStrategy; sql_hooks?: { - pre?: string | [string, ...string[]]; + pre?: string | [string, ...string[]] | null; post?: string | [string, ...string[]]; }; partitioned_by?: [string, ...string[]]; diff --git a/src/shared/schema/types/model.schema.d.ts b/src/shared/schema/types/model.schema.d.ts index ef9f4a7..99adf74 100644 --- a/src/shared/schema/types/model.schema.d.ts +++ b/src/shared/schema/types/model.schema.d.ts @@ -996,9 +996,9 @@ export interface ModelSqlHooksSchemaJson { */ post?: string | [string, ...string[]]; /** - * Statement(s) to run before model + * Statement(s) to run before the model. Omit to use DJ's incremental session pre-hook. null disables that hook. A string or array replaces it. */ - pre?: string | [string, ...string[]]; + pre?: string | [string, ...string[]] | null; } export interface SchemaColumnLightdash { case_sensitive?: SchemaLightdashCaseSensitive; diff --git a/src/shared/schema/types/model.sql_hooks.schema.d.ts b/src/shared/schema/types/model.sql_hooks.schema.d.ts index be91863..53b86f0 100644 --- a/src/shared/schema/types/model.sql_hooks.schema.d.ts +++ b/src/shared/schema/types/model.sql_hooks.schema.d.ts @@ -14,7 +14,7 @@ export interface ModelSqlHooksSchemaJson { */ post?: string | [string, ...string[]]; /** - * Statement(s) to run before model + * Statement(s) to run before the model. Omit to use DJ's incremental session pre-hook. null disables that hook. A string or array replaces it. */ - pre?: string | [string, ...string[]]; + pre?: string | [string, ...string[]] | null; } diff --git a/src/shared/schema/types/model.type.int_join_column.schema.d.ts b/src/shared/schema/types/model.type.int_join_column.schema.d.ts index af63d00..bf0b23b 100644 --- a/src/shared/schema/types/model.type.int_join_column.schema.d.ts +++ b/src/shared/schema/types/model.type.int_join_column.schema.d.ts @@ -562,9 +562,9 @@ export interface ModelSqlHooksSchemaJson { */ post?: string | [string, ...string[]]; /** - * Statement(s) to run before model + * Statement(s) to run before the model. Omit to use DJ's incremental session pre-hook. null disables that hook. A string or array replaces it. */ - pre?: string | [string, ...string[]]; + pre?: string | [string, ...string[]] | null; } /** * Defines an inline subquery for use in WHERE or HAVING conditions. Supports IN, NOT IN, EXISTS, NOT EXISTS, and scalar comparison operators. diff --git a/src/shared/schema/types/model.type.int_join_models.schema.d.ts b/src/shared/schema/types/model.type.int_join_models.schema.d.ts index b0eb975..db5fba8 100644 --- a/src/shared/schema/types/model.type.int_join_models.schema.d.ts +++ b/src/shared/schema/types/model.type.int_join_models.schema.d.ts @@ -1069,9 +1069,9 @@ export interface ModelSqlHooksSchemaJson { */ post?: string | [string, ...string[]]; /** - * Statement(s) to run before model + * Statement(s) to run before the model. Omit to use DJ's incremental session pre-hook. null disables that hook. A string or array replaces it. */ - pre?: string | [string, ...string[]]; + pre?: string | [string, ...string[]] | null; } /** * Defines an inline subquery for use in WHERE or HAVING conditions. Supports IN, NOT IN, EXISTS, NOT EXISTS, and scalar comparison operators. diff --git a/src/shared/schema/types/model.type.int_lookback_model.schema.d.ts b/src/shared/schema/types/model.type.int_lookback_model.schema.d.ts index 53b55ee..eea04bb 100644 --- a/src/shared/schema/types/model.type.int_lookback_model.schema.d.ts +++ b/src/shared/schema/types/model.type.int_lookback_model.schema.d.ts @@ -759,9 +759,9 @@ export interface ModelSqlHooksSchemaJson { */ post?: string | [string, ...string[]]; /** - * Statement(s) to run before model + * Statement(s) to run before the model. Omit to use DJ's incremental session pre-hook. null disables that hook. A string or array replaces it. */ - pre?: string | [string, ...string[]]; + pre?: string | [string, ...string[]] | null; } export interface SchemaColumnLightdash { case_sensitive?: SchemaLightdashCaseSensitive; diff --git a/src/shared/schema/types/model.type.int_rollup_model.schema.d.ts b/src/shared/schema/types/model.type.int_rollup_model.schema.d.ts index 14a7039..c5f6a36 100644 --- a/src/shared/schema/types/model.type.int_rollup_model.schema.d.ts +++ b/src/shared/schema/types/model.type.int_rollup_model.schema.d.ts @@ -426,9 +426,9 @@ export interface ModelSqlHooksSchemaJson { */ post?: string | [string, ...string[]]; /** - * Statement(s) to run before model + * Statement(s) to run before the model. Omit to use DJ's incremental session pre-hook. null disables that hook. A string or array replaces it. */ - pre?: string | [string, ...string[]]; + pre?: string | [string, ...string[]] | null; } /** * Rollup configuration for time-grain re-aggregation diff --git a/src/shared/schema/types/model.type.int_select_model.schema.d.ts b/src/shared/schema/types/model.type.int_select_model.schema.d.ts index 99e2b8a..114cfaf 100644 --- a/src/shared/schema/types/model.type.int_select_model.schema.d.ts +++ b/src/shared/schema/types/model.type.int_select_model.schema.d.ts @@ -1071,9 +1071,9 @@ export interface ModelSqlHooksSchemaJson { */ post?: string | [string, ...string[]]; /** - * Statement(s) to run before model + * Statement(s) to run before the model. Omit to use DJ's incremental session pre-hook. null disables that hook. A string or array replaces it. */ - pre?: string | [string, ...string[]]; + pre?: string | [string, ...string[]] | null; } /** * Defines an inline subquery for use in WHERE or HAVING conditions. Supports IN, NOT IN, EXISTS, NOT EXISTS, and scalar comparison operators. diff --git a/src/shared/schema/types/model.type.int_union_models.schema.d.ts b/src/shared/schema/types/model.type.int_union_models.schema.d.ts index 48b696c..bc093ca 100644 --- a/src/shared/schema/types/model.type.int_union_models.schema.d.ts +++ b/src/shared/schema/types/model.type.int_union_models.schema.d.ts @@ -1008,9 +1008,9 @@ export interface ModelSqlHooksSchemaJson { */ post?: string | [string, ...string[]]; /** - * Statement(s) to run before model + * Statement(s) to run before the model. Omit to use DJ's incremental session pre-hook. null disables that hook. A string or array replaces it. */ - pre?: string | [string, ...string[]]; + pre?: string | [string, ...string[]] | null; } /** * Defines a Common Table Expression (CTE) within a model. CTEs are lightweight intermediate transformations that generate SQL WITH clauses. diff --git a/src/shared/schema/types/model.type.stg_select_model.schema.d.ts b/src/shared/schema/types/model.type.stg_select_model.schema.d.ts index ecb38cc..cbe0355 100644 --- a/src/shared/schema/types/model.type.stg_select_model.schema.d.ts +++ b/src/shared/schema/types/model.type.stg_select_model.schema.d.ts @@ -513,9 +513,9 @@ export interface ModelSqlHooksSchemaJson { */ post?: string | [string, ...string[]]; /** - * Statement(s) to run before model + * Statement(s) to run before the model. Omit to use DJ's incremental session pre-hook. null disables that hook. A string or array replaces it. */ - pre?: string | [string, ...string[]]; + pre?: string | [string, ...string[]] | null; } /** * Defines an inline subquery for use in WHERE or HAVING conditions. Supports IN, NOT IN, EXISTS, NOT EXISTS, and scalar comparison operators. diff --git a/src/shared/schema/types/model.type.stg_select_source.schema.d.ts b/src/shared/schema/types/model.type.stg_select_source.schema.d.ts index 7741e51..049f5db 100644 --- a/src/shared/schema/types/model.type.stg_select_source.schema.d.ts +++ b/src/shared/schema/types/model.type.stg_select_source.schema.d.ts @@ -504,9 +504,9 @@ export interface ModelSqlHooksSchemaJson { */ post?: string | [string, ...string[]]; /** - * Statement(s) to run before model + * Statement(s) to run before the model. Omit to use DJ's incremental session pre-hook. null disables that hook. A string or array replaces it. */ - pre?: string | [string, ...string[]]; + pre?: string | [string, ...string[]] | null; } export interface SchemaColumnLightdash { case_sensitive?: SchemaLightdashCaseSensitive; diff --git a/src/shared/schema/types/model.type.stg_union_sources.schema.d.ts b/src/shared/schema/types/model.type.stg_union_sources.schema.d.ts index a550f43..e011952 100644 --- a/src/shared/schema/types/model.type.stg_union_sources.schema.d.ts +++ b/src/shared/schema/types/model.type.stg_union_sources.schema.d.ts @@ -508,9 +508,9 @@ export interface ModelSqlHooksSchemaJson { */ post?: string | [string, ...string[]]; /** - * Statement(s) to run before model + * Statement(s) to run before the model. Omit to use DJ's incremental session pre-hook. null disables that hook. A string or array replaces it. */ - pre?: string | [string, ...string[]]; + pre?: string | [string, ...string[]] | null; } export interface SchemaColumnLightdash { case_sensitive?: SchemaLightdashCaseSensitive; diff --git a/tests/fixtures/manifest.json b/tests/fixtures/manifest.json index a722d87..45507b2 100644 --- a/tests/fixtures/manifest.json +++ b/tests/fixtures/manifest.json @@ -1 +1 @@ -{"metadata":{"dbt_schema_version":"https://schemas.getdbt.com/dbt/manifest/v12.json","dbt_version":"1.10.17","generated_at":"2026-05-04T13:21:53.112125Z","invocation_id":"aff8a422-d597-4b53-b155-301a8038905a","invocation_started_at":"2026-05-04T13:08:16.905880+00:00","env":{},"project_name":"jaffle_shop","project_id":"06e5b98c2db46f8a72cc4f66410e9b3b","user_id":null,"send_anonymous_usage_stats":false,"adapter_type":"trino","quoting":{"database":false,"schema":false,"identifier":false,"column":null}},"nodes":{"model.jaffle_shop.stg__customers__profiles__clean":{"database":"development","schema":"jaffle_shop_dev_staging","name":"stg__customers__profiles__clean","resource_type":"model","package_name":"jaffle_shop","path":"staging/customers/profiles/stg__customers__profiles__clean.sql","original_file_path":"models/staging/customers/profiles/stg__customers__profiles__clean.sql","unique_id":"model.jaffle_shop.stg__customers__profiles__clean","fqn":["jaffle_shop","staging","customers","profiles","stg__customers__profiles__clean"],"alias":"stg__customers__profiles__clean","checksum":{"name":"sha256","checksum":"287111d3952cfe726dbe9e981ee7081b346589275a6360c596261ca94f51a776"},"config":{"enabled":true,"alias":null,"schema":"staging","database":null,"tags":["json","staging"],"meta":{},"group":"customers","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#B6AB33"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","staging"],"description":"","columns":{"customer_first_name":{"name":"customer_first_name","description":"Customer first name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_id":{"name":"customer_id","description":"Unique identifier for each customer","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_last_name":{"name":"customer_last_name","description":"Customer last name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_name":{"name":"customer_name","description":"Customer full name, trimmed of whitespace","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"customers","docs":{"show":true,"node_color":"#B6AB33"},"patch_path":"jaffle_shop://models/staging/customers/profiles/stg__customers__profiles__clean.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","schema":"staging","group":"customers","tags":["json","staging"],"docs":{"node_color":"#B6AB33","show":true},"contract":{"enforced":false}},"created_at":1777900097.9705758,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tstg__customers__profiles__clean AS (\n\t\tSELECT\n\t\t\tsplit(TRIM(name), ' ') [1] AS customer_first_name,\n\t\t\tid AS customer_id,\n\t\t\tCASE\n\t\t\t\tWHEN cardinality(split(TRIM(name), ' ')) > 1 THEN split(TRIM(name), ' ') [cardinality(split(TRIM(name), ' '))]\n\t\t\t\tELSE NULL\n\t\t\tEND AS customer_last_name,\n\t\t\tTRIM(name) AS customer_name,\n\t\t\t1 AS portal_source_count\n\t\tFROM\n\t\t\t{{ source('development__jaffle_shop_dev_seeds','raw_customers') }}\n\t)\nSELECT\n\t*\nFROM\n\tstg__customers__profiles__clean","doc_blocks":[],"language":"sql","refs":[],"sources":[["development__jaffle_shop_dev_seeds","raw_customers"]],"metrics":[],"depends_on":{"macros":[],"nodes":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_customers"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.stg__products__catalog__catalog":{"database":"development","schema":"jaffle_shop_dev_staging","name":"stg__products__catalog__catalog","resource_type":"model","package_name":"jaffle_shop","path":"staging/products/catalog/stg__products__catalog__catalog.sql","original_file_path":"models/staging/products/catalog/stg__products__catalog__catalog.sql","unique_id":"model.jaffle_shop.stg__products__catalog__catalog","fqn":["jaffle_shop","staging","products","catalog","stg__products__catalog__catalog"],"alias":"stg__products__catalog__catalog","checksum":{"name":"sha256","checksum":"9dc9de44d2bf73d9d9a961d348ae987846711bc1695ed792141e8aa513fd224a"},"config":{"enabled":true,"alias":null,"schema":"staging","database":null,"tags":["json","staging"],"meta":{},"group":"products","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#B6AB33"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","staging"],"description":"","columns":{"description":{"name":"description","description":"Product description","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"is_beverage":{"name":"is_beverage","description":"Boolean flag for beverage products","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"is_jaffle":{"name":"is_jaffle","description":"Boolean flag for jaffle products","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_name":{"name":"product_name","description":"Product name, trimmed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_price_cents":{"name":"product_price_cents","description":"Product price in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_price_dollars":{"name":"product_price_dollars","description":"Product price in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_sku":{"name":"product_sku","description":"Product SKU identifier","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_type":{"name":"product_type","description":"Product category (jaffle, beverage)","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"products","docs":{"show":true,"node_color":"#B6AB33"},"patch_path":"jaffle_shop://models/staging/products/catalog/stg__products__catalog__catalog.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","schema":"staging","group":"products","tags":["json","staging"],"docs":{"node_color":"#B6AB33","show":true},"contract":{"enforced":false}},"created_at":1777900097.9725068,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tstg__products__catalog__catalog AS (\n\t\tSELECT\n\t\t\tTRIM(description) AS description,\n\t\t\tLOWER(TRIM(TYPE)) = 'beverage' AS is_beverage,\n\t\t\tLOWER(TRIM(TYPE)) = 'jaffle' AS is_jaffle,\n\t\t\t1 AS portal_source_count,\n\t\t\tTRIM(name) AS product_name,\n\t\t\tprice AS product_price_cents,\n\t\t\tCAST(price AS DECIMAL(10, 2)) / 100.0 AS product_price_dollars,\n\t\t\tsku AS product_sku,\n\t\t\tTRIM(TYPE) AS product_type\n\t\tFROM\n\t\t\t{{ source('development__jaffle_shop_dev_seeds','raw_products') }}\n\t)\nSELECT\n\t*\nFROM\n\tstg__products__catalog__catalog","doc_blocks":[],"language":"sql","refs":[],"sources":[["development__jaffle_shop_dev_seeds","raw_products"]],"metrics":[],"depends_on":{"macros":[],"nodes":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_products"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.stg__sales__stores__locations":{"database":"development","schema":"jaffle_shop_dev_staging","name":"stg__sales__stores__locations","resource_type":"model","package_name":"jaffle_shop","path":"staging/sales/stores/stg__sales__stores__locations.sql","original_file_path":"models/staging/sales/stores/stg__sales__stores__locations.sql","unique_id":"model.jaffle_shop.stg__sales__stores__locations","fqn":["jaffle_shop","staging","sales","stores","stg__sales__stores__locations"],"alias":"stg__sales__stores__locations","checksum":{"name":"sha256","checksum":"f540771873516a9be7d0c9255e6cb666d633e2aeceb3236f8f3a00dd7dbc5b40"},"config":{"enabled":true,"alias":null,"schema":"staging","database":null,"tags":["json","staging"],"meta":{},"group":"sales","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#B6AB33"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","staging"],"description":"","columns":{"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"Unique identifier for each store","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_name":{"name":"store_name","description":"Store location name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_opened_at":{"name":"store_opened_at","description":"Timestamp when store opened","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_opened_date":{"name":"store_opened_date","description":"Date when store opened","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_tax_rate":{"name":"store_tax_rate","description":"Local tax rate for the store","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_tax_rate_percent":{"name":"store_tax_rate_percent","description":"Tax rate as percentage","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"sales","docs":{"show":true,"node_color":"#B6AB33"},"patch_path":"jaffle_shop://models/staging/sales/stores/stg__sales__stores__locations.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","schema":"staging","group":"sales","tags":["json","staging"],"docs":{"node_color":"#B6AB33","show":true},"contract":{"enforced":false}},"created_at":1777900097.973921,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tstg__sales__stores__locations AS (\n\t\tSELECT\n\t\t\t1 AS portal_source_count,\n\t\t\tid AS store_id,\n\t\t\tTRIM(name) AS store_name,\n\t\t\tCAST(opened_at AS TIMESTAMP) AS store_opened_at,\n\t\t\tDATE(CAST(opened_at AS TIMESTAMP)) AS store_opened_date,\n\t\t\ttax_rate AS store_tax_rate,\n\t\t\ttax_rate * 100 AS store_tax_rate_percent\n\t\tFROM\n\t\t\t{{ source('development__jaffle_shop_dev_seeds','raw_stores') }}\n\t)\nSELECT\n\t*\nFROM\n\tstg__sales__stores__locations","doc_blocks":[],"language":"sql","refs":[],"sources":[["development__jaffle_shop_dev_seeds","raw_stores"]],"metrics":[],"depends_on":{"macros":[],"nodes":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_stores"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.stg__sales__orders__standardized":{"database":"development","schema":"jaffle_shop_dev_staging","name":"stg__sales__orders__standardized","resource_type":"model","package_name":"jaffle_shop","path":"staging/sales/orders/stg__sales__orders__standardized.sql","original_file_path":"models/staging/sales/orders/stg__sales__orders__standardized.sql","unique_id":"model.jaffle_shop.stg__sales__orders__standardized","fqn":["jaffle_shop","staging","sales","orders","stg__sales__orders__standardized"],"alias":"stg__sales__orders__standardized","checksum":{"name":"sha256","checksum":"c6f5fb75f6eb8b31fb5d26838e257c14b2330b60f5b4b289a0a16a92330d58f7"},"config":{"enabled":true,"alias":null,"schema":"staging","database":null,"tags":["json","staging"],"meta":{},"group":"sales","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#B6AB33"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","staging"],"description":"","columns":{"customer_id":{"name":"customer_id","description":"Foreign key to customer","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_date":{"name":"order_date","description":"Date when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_id":{"name":"order_id","description":"Unique identifier for each order","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total_cents":{"name":"order_total_cents","description":"Total order amount in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"ordered_at":{"name":"ordered_at","description":"Timestamp when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"Foreign key to store","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"subtotal_cents":{"name":"subtotal_cents","description":"Order subtotal in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"tax_paid_cents":{"name":"tax_paid_cents","description":"Tax amount paid in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"sales","docs":{"show":true,"node_color":"#B6AB33"},"patch_path":"jaffle_shop://models/staging/sales/orders/stg__sales__orders__standardized.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","schema":"staging","group":"sales","tags":["json","staging"],"docs":{"node_color":"#B6AB33","show":true},"contract":{"enforced":false}},"created_at":1777900097.975872,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tstg__sales__orders__standardized AS (\n\t\tSELECT\n\t\t\tcustomer AS customer_id,\n\t\t\tDATE(CAST(ordered_at AS TIMESTAMP)) AS order_date,\n\t\t\tid AS order_id,\n\t\t\torder_total AS order_total_cents,\n\t\t\tCAST(ordered_at AS TIMESTAMP) AS ordered_at,\n\t\t\t1 AS portal_source_count,\n\t\t\tstore_id AS store_id,\n\t\t\tsubtotal AS subtotal_cents,\n\t\t\ttax_paid AS tax_paid_cents\n\t\tFROM\n\t\t\t{{ source('development__jaffle_shop_dev_seeds','raw_orders') }}\n\t)\nSELECT\n\t*\nFROM\n\tstg__sales__orders__standardized","doc_blocks":[],"language":"sql","refs":[],"sources":[["development__jaffle_shop_dev_seeds","raw_orders"]],"metrics":[],"depends_on":{"macros":[],"nodes":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_orders"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.stg__sales__items__order_details":{"database":"development","schema":"jaffle_shop_dev_staging","name":"stg__sales__items__order_details","resource_type":"model","package_name":"jaffle_shop","path":"staging/sales/items/stg__sales__items__order_details.sql","original_file_path":"models/staging/sales/items/stg__sales__items__order_details.sql","unique_id":"model.jaffle_shop.stg__sales__items__order_details","fqn":["jaffle_shop","staging","sales","items","stg__sales__items__order_details"],"alias":"stg__sales__items__order_details","checksum":{"name":"sha256","checksum":"3e1cb4978cc09f8884d2012ddd69b41ff08fda10376e04b342723e7c8dc4641a"},"config":{"enabled":true,"alias":null,"schema":"staging","database":null,"tags":["json","staging"],"meta":{},"group":"sales","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#B6AB33"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","staging"],"description":"","columns":{"is_beverage_item":{"name":"is_beverage_item","description":"Boolean flag for beverage items","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"is_jaffle_item":{"name":"is_jaffle_item","description":"Boolean flag for jaffle items","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"item_id":{"name":"item_id","description":"Unique identifier for each order item","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_id":{"name":"order_id","description":"Foreign key to orders table","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_sku":{"name":"product_sku","description":"Product SKU identifier","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_type":{"name":"product_type","description":"Product type derived from SKU pattern","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"sales","docs":{"show":true,"node_color":"#B6AB33"},"patch_path":"jaffle_shop://models/staging/sales/items/stg__sales__items__order_details.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","schema":"staging","group":"sales","tags":["json","staging"],"docs":{"node_color":"#B6AB33","show":true},"contract":{"enforced":false}},"created_at":1777900097.977076,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tstg__sales__items__order_details AS (\n\t\tSELECT\n\t\t\tsku LIKE 'BEV-%' AS is_beverage_item,\n\t\t\tsku LIKE 'JAF-%' AS is_jaffle_item,\n\t\t\tid AS item_id,\n\t\t\torder_id AS order_id,\n\t\t\t1 AS portal_source_count,\n\t\t\tsku AS product_sku,\n\t\t\tCASE\n\t\t\t\tWHEN sku LIKE 'JAF-%' THEN 'jaffle'\n\t\t\t\tWHEN sku LIKE 'BEV-%' THEN 'beverage'\n\t\t\t\tELSE 'unknown'\n\t\t\tEND AS product_type\n\t\tFROM\n\t\t\t{{ source('development__jaffle_shop_dev_seeds','raw_items') }}\n\t)\nSELECT\n\t*\nFROM\n\tstg__sales__items__order_details","doc_blocks":[],"language":"sql","refs":[],"sources":[["development__jaffle_shop_dev_seeds","raw_items"]],"metrics":[],"depends_on":{"macros":[],"nodes":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_items"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.stg__supply_chain__supplies__inventory":{"database":"development","schema":"jaffle_shop_dev_staging","name":"stg__supply_chain__supplies__inventory","resource_type":"model","package_name":"jaffle_shop","path":"staging/supply_chain/supplies/stg__supply_chain__supplies__inventory.sql","original_file_path":"models/staging/supply_chain/supplies/stg__supply_chain__supplies__inventory.sql","unique_id":"model.jaffle_shop.stg__supply_chain__supplies__inventory","fqn":["jaffle_shop","staging","supply_chain","supplies","stg__supply_chain__supplies__inventory"],"alias":"stg__supply_chain__supplies__inventory","checksum":{"name":"sha256","checksum":"1809b8f0c6f71c29c5300ad12fdacfec24bc22280612dcd2a8ebadc7d3c6f5d6"},"config":{"enabled":true,"alias":null,"schema":"staging","database":null,"tags":["json","staging"],"meta":{},"group":"supply_chain","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#B6AB33"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","staging"],"description":"","columns":{"cost_cents":{"name":"cost_cents","description":"Supply cost in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"cost_dollars":{"name":"cost_dollars","description":"Supply cost in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"is_perishable":{"name":"is_perishable","description":"Boolean flag for perishable supplies","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_sku":{"name":"product_sku","description":"Associated product SKU","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"supply_category":{"name":"supply_category","description":"Supply category classification","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"supply_id":{"name":"supply_id","description":"Unique identifier for each supply item","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"supply_name":{"name":"supply_name","description":"Supply item name, trimmed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"supply_chain","docs":{"show":true,"node_color":"#B6AB33"},"patch_path":"jaffle_shop://models/staging/supply_chain/supplies/stg__supply_chain__supplies__inventory.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","schema":"staging","group":"supply_chain","tags":["json","staging"],"docs":{"node_color":"#B6AB33","show":true},"contract":{"enforced":false}},"created_at":1777900097.978841,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tstg__supply_chain__supplies__inventory AS (\n\t\tSELECT\n\t\t\tcost AS cost_cents,\n\t\t\tCAST(cost AS DECIMAL(10, 2)) / 100.0 AS cost_dollars,\n\t\t\tCASE\n\t\t\t\tWHEN perishable = TRUE THEN TRUE\n\t\t\t\tELSE FALSE\n\t\t\tEND AS is_perishable,\n\t\t\t1 AS portal_source_count,\n\t\t\tsku AS product_sku,\n\t\t\tCASE\n\t\t\t\tWHEN LOWER(name) LIKE '%cutlery%'\n\t\t\t\tOR LOWER(name) LIKE '%fork%'\n\t\t\t\tOR LOWER(name) LIKE '%knife%' THEN 'utensils'\n\t\t\t\tWHEN LOWER(name) LIKE '%napkin%'\n\t\t\t\tOR LOWER(name) LIKE '%boat%' THEN 'packaging'\n\t\t\t\tWHEN perishable = TRUE THEN 'ingredients'\n\t\t\t\tELSE 'other'\n\t\t\tEND AS supply_category,\n\t\t\tid AS supply_id,\n\t\t\tTRIM(name) AS supply_name\n\t\tFROM\n\t\t\t{{ source('development__jaffle_shop_dev_seeds','raw_supplies') }}\n\t)\nSELECT\n\t*\nFROM\n\tstg__supply_chain__supplies__inventory","doc_blocks":[],"language":"sql","refs":[],"sources":[["development__jaffle_shop_dev_seeds","raw_supplies"]],"metrics":[],"depends_on":{"macros":[],"nodes":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_supplies"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.mart__customers__dashboard__analytics":{"database":"development","schema":"jaffle_shop_dev","name":"mart__customers__dashboard__analytics","resource_type":"model","package_name":"jaffle_shop","path":"marts/customers/dashboard/mart__customers__dashboard__analytics.sql","original_file_path":"models/marts/customers/dashboard/mart__customers__dashboard__analytics.sql","unique_id":"model.jaffle_shop.mart__customers__dashboard__analytics","fqn":["jaffle_shop","marts","customers","dashboard","mart__customers__dashboard__analytics"],"alias":"mart__customers__dashboard__analytics","checksum":{"name":"sha256","checksum":"d74eb1171643e36fdf8303e9d0ede6fde081029d1b3378551e46c2b5d261f72a"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["json","lightdash-explore","mart"],"meta":{},"group":"customers","materialized":"view","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#059669"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","lightdash-explore","mart"],"description":"","columns":{"customer_first_name":{"name":"customer_first_name","description":"Customer first name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"},"dimension":{"type":"string","label":"Customer First Name"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"},"dimension":{"type":"string","label":"Customer First Name"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_id":{"name":"customer_id","description":"Unique identifier for each customer","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"},"dimension":{"type":"string","label":"Customer Id"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"},"dimension":{"type":"string","label":"Customer Id"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_last_name":{"name":"customer_last_name","description":"Customer last name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"},"dimension":{"type":"string","label":"Customer Last Name"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"},"dimension":{"type":"string","label":"Customer Last Name"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_name":{"name":"customer_name","description":"Customer full name, trimmed of whitespace","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"},"dimension":{"type":"string","label":"Customer Name"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"},"dimension":{"type":"string","label":"Customer Name"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_segment":{"name":"customer_segment","description":"Customer segment classification based on order count","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__customers__dashboard__analytics"},"dimension":{"type":"string","label":"Customer Segment"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__customers__dashboard__analytics"},"dimension":{"type":"string","label":"Customer Segment"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"has_last_name":{"name":"has_last_name","description":"Whether customer provided a last name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.int__customers__profiles__summary"},"dimension":{"type":"string","label":"Has Last Name"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.int__customers__profiles__summary"},"dimension":{"type":"string","label":"Has Last Name"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"type":"number","label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"type":"number","label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_orders":{"name":"total_orders","description":"Total number of orders placed by customer","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__customers__profiles__summary"},"dimension":{"type":"string","label":"Total Orders","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__customers__profiles__summary"},"dimension":{"type":"string","label":"Total Orders","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"customers","docs":{"show":true,"node_color":"#059669"},"patch_path":"jaffle_shop://models/marts/customers/dashboard/mart__customers__dashboard__analytics.yml","build_path":null,"unrendered_config":{"materialized":"view","group":"customers","tags":["json","lightdash-explore","mart"],"docs":{"node_color":"#059669","show":true},"contract":{"enforced":false}},"created_at":1777900097.981371,"relation_name":"development.jaffle_shop_dev.mart__customers__dashboard__analytics","raw_code":"{{\n config(\n materialized=\"view\"\n )\n}}\n\nWITH\n\tmart__customers__dashboard__analytics AS (\n\t\tSELECT\n\t\t\tcustomer_first_name,\n\t\t\tcustomer_id,\n\t\t\tcustomer_last_name,\n\t\t\tcustomer_name,\n\t\t\tCASE\n\t\t\t\tWHEN total_orders >= 10 THEN 'VIP'\n\t\t\t\tWHEN total_orders >= 3 THEN 'Regular'\n\t\t\t\tELSE 'New'\n\t\t\tEND AS customer_segment,\n\t\t\thas_last_name,\n\t\t\tportal_source_count,\n\t\t\ttotal_orders\n\t\tFROM\n\t\t\t{{ ref('int__customers__profiles__summary') }}\n\t)\nSELECT\n\t*\nFROM\n\tmart__customers__dashboard__analytics","doc_blocks":[],"language":"sql","refs":[{"name":"int__customers__profiles__summary","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.int__customers__profiles__summary"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.mart__products__reporting__cost_efficiency":{"database":"development","schema":"jaffle_shop_dev","name":"mart__products__reporting__cost_efficiency","resource_type":"model","package_name":"jaffle_shop","path":"marts/products/reporting/mart__products__reporting__cost_efficiency.sql","original_file_path":"models/marts/products/reporting/mart__products__reporting__cost_efficiency.sql","unique_id":"model.jaffle_shop.mart__products__reporting__cost_efficiency","fqn":["jaffle_shop","marts","products","reporting","mart__products__reporting__cost_efficiency"],"alias":"mart__products__reporting__cost_efficiency","checksum":{"name":"sha256","checksum":"d36e0bd5cc45bd1e8d9636dfaa9b1fa96cc06b5612eaba5f658f3ddbcb9e3b49"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["json","lightdash-explore","mart"],"meta":{},"group":"products","materialized":"view","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#059669"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","lightdash-explore","mart"],"description":"","columns":{"cost_efficiency_category":{"name":"cost_efficiency_category","description":"Cost efficiency classification","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Cost Efficiency Category"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Cost Efficiency Category"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"cost_to_price_ratio":{"name":"cost_to_price_ratio","description":"Individual supply cost as ratio of selling price","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Cost To Price Ratio","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Cost To Price Ratio","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"is_perishable_supply":{"name":"is_perishable_supply","description":"Whether this supply is perishable","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Is Perishable Supply"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Is Perishable Supply"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"perishable_risk_level":{"name":"perishable_risk_level","description":"Risk level based on perishable supplies","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Perishable Risk Level"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Perishable Risk Level"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"type":"number","label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"type":"number","label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_name":{"name":"product_name","description":"Product name, trimmed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"},"dimension":{"type":"string","label":"Product Name"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"},"dimension":{"type":"string","label":"Product Name"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_price_dollars":{"name":"product_price_dollars","description":"Product price in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"},"dimension":{"type":"string","label":"Product Price Dollars","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"},"dimension":{"type":"string","label":"Product Price Dollars","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_sku":{"name":"product_sku","description":"Associated product SKU","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"},"dimension":{"type":"string","label":"Product Sku"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"},"dimension":{"type":"string","label":"Product Sku"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_type":{"name":"product_type","description":"Product category (jaffle, beverage)","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"},"dimension":{"type":"string","label":"Product Type"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"},"dimension":{"type":"string","label":"Product Type"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"supply_cost_dollars":{"name":"supply_cost_dollars","description":"Individual supply cost in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Supply Cost Dollars","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Supply Cost Dollars","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"products","docs":{"show":true,"node_color":"#059669"},"patch_path":"jaffle_shop://models/marts/products/reporting/mart__products__reporting__cost_efficiency.yml","build_path":null,"unrendered_config":{"materialized":"view","group":"products","tags":["json","lightdash-explore","mart"],"docs":{"node_color":"#059669","show":true},"contract":{"enforced":false}},"created_at":1777900097.983947,"relation_name":"development.jaffle_shop_dev.mart__products__reporting__cost_efficiency","raw_code":"{{\n config(\n materialized=\"view\"\n )\n}}\n\nWITH\n\tmart__products__reporting__cost_efficiency AS (\n\t\tSELECT\n\t\t\tCASE\n\t\t\t\tWHEN cost_dollars / product_price_dollars <= 0.30 THEN 'Highly Efficient'\n\t\t\t\tWHEN cost_dollars / product_price_dollars <= 0.50 THEN 'Efficient'\n\t\t\t\tWHEN cost_dollars / product_price_dollars <= 0.70 THEN 'Moderate'\n\t\t\t\tELSE 'Low Efficiency'\n\t\t\tEND AS cost_efficiency_category,\n\t\t\tCASE\n\t\t\t\tWHEN product_price_dollars > 0 THEN cost_dollars / product_price_dollars\n\t\t\t\tELSE NULL\n\t\t\tEND AS cost_to_price_ratio,\n\t\t\tis_perishable AS is_perishable_supply,\n\t\t\tCASE\n\t\t\t\tWHEN is_perishable THEN 'High Risk'\n\t\t\t\tELSE 'Low Risk'\n\t\t\tEND AS perishable_risk_level,\n\t\t\tportal_source_count,\n\t\t\tproduct_name,\n\t\t\tproduct_price_dollars,\n\t\t\tproduct_sku,\n\t\t\tproduct_type,\n\t\t\tcost_dollars AS supply_cost_dollars\n\t\tFROM\n\t\t\t{{ ref('int__supply_chain__supplies__cost_analysis') }}\n\t)\nSELECT\n\t*\nFROM\n\tmart__products__reporting__cost_efficiency","doc_blocks":[],"language":"sql","refs":[{"name":"int__supply_chain__supplies__cost_analysis","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.int__supply_chain__supplies__cost_analysis"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.mart__products__reporting__menu_analytics":{"database":"development","schema":"jaffle_shop_dev","name":"mart__products__reporting__menu_analytics","resource_type":"model","package_name":"jaffle_shop","path":"marts/products/reporting/mart__products__reporting__menu_analytics.sql","original_file_path":"models/marts/products/reporting/mart__products__reporting__menu_analytics.sql","unique_id":"model.jaffle_shop.mart__products__reporting__menu_analytics","fqn":["jaffle_shop","marts","products","reporting","mart__products__reporting__menu_analytics"],"alias":"mart__products__reporting__menu_analytics","checksum":{"name":"sha256","checksum":"a0f496985a432632cb87c7fbac4a525d8c9916d1ca1d201849f517601fb4e0fc"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["json","lightdash-explore","mart"],"meta":{},"group":"products","materialized":"view","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#059669"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","lightdash-explore","mart"],"description":"","columns":{"item_id":{"name":"item_id","description":"Unique identifier for each order item","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"},"dimension":{"type":"string","label":"Item Id"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"},"dimension":{"type":"string","label":"Item Id"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"type":"number","label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"type":"number","label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_sku":{"name":"product_sku","description":"Product SKU identifier","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"},"dimension":{"type":"string","label":"Product Sku"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"},"dimension":{"type":"string","label":"Product Sku"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_type":{"name":"product_type","description":"Product type derived from SKU pattern","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"},"dimension":{"type":"string","label":"Product Type"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"},"dimension":{"type":"string","label":"Product Type"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_items_sold":{"name":"total_items_sold","description":"Total quantity of this product sold","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__products__analytics__product_popularity"},"dimension":{"type":"string","label":"Total Items Sold","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__products__analytics__product_popularity"},"dimension":{"type":"string","label":"Total Items Sold","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_orders":{"name":"total_orders","description":"Number of unique orders containing this product","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__products__analytics__product_popularity"},"dimension":{"type":"string","label":"Total Orders","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__products__analytics__product_popularity"},"dimension":{"type":"string","label":"Total Orders","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"products","docs":{"show":true,"node_color":"#059669"},"patch_path":"jaffle_shop://models/marts/products/reporting/mart__products__reporting__menu_analytics.yml","build_path":null,"unrendered_config":{"materialized":"view","group":"products","tags":["json","lightdash-explore","mart"],"docs":{"node_color":"#059669","show":true},"contract":{"enforced":false}},"created_at":1777900097.985304,"relation_name":"development.jaffle_shop_dev.mart__products__reporting__menu_analytics","raw_code":"{{\n config(\n materialized=\"view\"\n )\n}}\n\nWITH\n\tmart__products__reporting__menu_analytics AS (\n\t\tSELECT\n\t\t\titem_id,\n\t\t\tportal_source_count,\n\t\t\tproduct_sku,\n\t\t\tproduct_type,\n\t\t\ttotal_items_sold,\n\t\t\ttotal_orders\n\t\tFROM\n\t\t\t{{ ref('int__products__analytics__product_popularity') }}\n\t)\nSELECT\n\t*\nFROM\n\tmart__products__reporting__menu_analytics","doc_blocks":[],"language":"sql","refs":[{"name":"int__products__analytics__product_popularity","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.int__products__analytics__product_popularity"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.mart__sales__reporting__revenue":{"database":"development","schema":"jaffle_shop_dev","name":"mart__sales__reporting__revenue","resource_type":"model","package_name":"jaffle_shop","path":"marts/sales/reporting/mart__sales__reporting__revenue.sql","original_file_path":"models/marts/sales/reporting/mart__sales__reporting__revenue.sql","unique_id":"model.jaffle_shop.mart__sales__reporting__revenue","fqn":["jaffle_shop","marts","sales","reporting","mart__sales__reporting__revenue"],"alias":"mart__sales__reporting__revenue","checksum":{"name":"sha256","checksum":"228949d9803f147afdcc929fe95d006fd04b9d4d4464f23ecdf458fcc9c16750"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["json","lightdash-explore","mart"],"meta":{},"group":"sales","materialized":"view","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#059669"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","lightdash-explore","mart"],"description":"","columns":{"customer_id":{"name":"customer_id","description":"Foreign key to customer","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"},"dimension":{"type":"string","label":"Customer Id"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"},"dimension":{"type":"string","label":"Customer Id"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_name":{"name":"customer_name","description":"Customer full name, trimmed of whitespace","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"},"dimension":{"type":"string","label":"Customer Name"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"},"dimension":{"type":"string","label":"Customer Name"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"is_weekend_order":{"name":"is_weekend_order","description":"Boolean flag for weekend orders","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Is Weekend Order"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Is Weekend Order"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_date":{"name":"order_date","description":"Date when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"},"dimension":{"type":"string","label":"Order Date"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"},"dimension":{"type":"string","label":"Order Date"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_id":{"name":"order_id","description":"Unique identifier for each order","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"},"dimension":{"type":"string","label":"Order Id"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"},"dimension":{"type":"string","label":"Order Id"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_month":{"name":"order_month","description":"Order month","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Order Month"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Order Month"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_quarter":{"name":"order_quarter","description":"Order quarter","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Order Quarter"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Order Quarter"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_year":{"name":"order_year","description":"Order year","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Order Year"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Order Year"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"type":"number","label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"type":"number","label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"revenue_tier":{"name":"revenue_tier","description":"Revenue tier classification","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Revenue Tier"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Revenue Tier"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"Foreign key to store","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"},"dimension":{"type":"string","label":"Store Id"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"},"dimension":{"type":"string","label":"Store Id"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_name":{"name":"store_name","description":"Store location name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"},"dimension":{"type":"string","label":"Store Name"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"},"dimension":{"type":"string","label":"Store Name"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"subtotal_dollars":{"name":"subtotal_dollars","description":"Order subtotal in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Subtotal Dollars","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Subtotal Dollars","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"tax_dollars":{"name":"tax_dollars","description":"Tax amount in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Tax Dollars","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Tax Dollars","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_dollars":{"name":"total_dollars","description":"Total order amount in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Total Dollars","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Total Dollars","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"sales","docs":{"show":true,"node_color":"#059669"},"patch_path":"jaffle_shop://models/marts/sales/reporting/mart__sales__reporting__revenue.yml","build_path":null,"unrendered_config":{"materialized":"view","group":"sales","tags":["json","lightdash-explore","mart"],"docs":{"node_color":"#059669","show":true},"contract":{"enforced":false}},"created_at":1777900097.988441,"relation_name":"development.jaffle_shop_dev.mart__sales__reporting__revenue","raw_code":"{{\n config(\n materialized=\"view\"\n )\n}}\n\nWITH\n\tmart__sales__reporting__revenue AS (\n\t\tSELECT\n\t\t\tcustomer_id,\n\t\t\tcustomer_name,\n\t\t\tday_of_week(order_date) IN (6, 7) AS is_weekend_order,\n\t\t\torder_date,\n\t\t\torder_id,\n\t\t\tEXTRACT(\n\t\t\t\tMONTH\n\t\t\t\tFROM\n\t\t\t\t\torder_date\n\t\t\t) AS order_month,\n\t\t\tEXTRACT(\n\t\t\t\tQUARTER\n\t\t\t\tFROM\n\t\t\t\t\torder_date\n\t\t\t) AS order_quarter,\n\t\t\tEXTRACT(\n\t\t\t\tYEAR\n\t\t\t\tFROM\n\t\t\t\t\torder_date\n\t\t\t) AS order_year,\n\t\t\tportal_source_count,\n\t\t\tCASE\n\t\t\t\tWHEN order_total_dollars >= 15.00 THEN 'High'\n\t\t\t\tWHEN order_total_dollars >= 8.00 THEN 'Medium'\n\t\t\t\tELSE 'Low'\n\t\t\tEND AS revenue_tier,\n\t\t\tstore_id,\n\t\t\tstore_name,\n\t\t\tCAST(subtotal_cents AS DECIMAL(10, 2)) / 100.0 AS subtotal_dollars,\n\t\t\tCAST(tax_paid_cents AS DECIMAL(10, 2)) / 100.0 AS tax_dollars,\n\t\t\torder_total_dollars AS total_dollars\n\t\tFROM\n\t\t\t{{ ref('int__sales__orders__enriched') }}\n\t)\nSELECT\n\t*\nFROM\n\tmart__sales__reporting__revenue","doc_blocks":[],"language":"sql","refs":[{"name":"int__sales__orders__enriched","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.int__sales__orders__enriched"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.mart__sales__reporting__profitability":{"database":"development","schema":"jaffle_shop_dev","name":"mart__sales__reporting__profitability","resource_type":"model","package_name":"jaffle_shop","path":"marts/sales/reporting/mart__sales__reporting__profitability.sql","original_file_path":"models/marts/sales/reporting/mart__sales__reporting__profitability.sql","unique_id":"model.jaffle_shop.mart__sales__reporting__profitability","fqn":["jaffle_shop","marts","sales","reporting","mart__sales__reporting__profitability"],"alias":"mart__sales__reporting__profitability","checksum":{"name":"sha256","checksum":"9e8829af38433ae219ddae8f68a8a2b4b976f679185a9ddb8b4666f440732cea"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["json","lightdash-explore","mart"],"meta":{},"group":"sales","materialized":"view","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#059669"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","lightdash-explore","mart"],"description":"","columns":{"avg_order_value_dollars":{"name":"avg_order_value_dollars","description":"Average order value in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__profitability"},"dimension":{"type":"string","label":"Avg Order Value Dollars","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__profitability"},"dimension":{"type":"string","label":"Avg Order Value Dollars","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_count":{"name":"order_count","description":"Number of orders","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__profitability"},"dimension":{"type":"string","label":"Order Count","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__profitability"},"dimension":{"type":"string","label":"Order Count","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_date":{"name":"order_date","description":"Date when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"},"dimension":{"type":"string","label":"Order Date"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"},"dimension":{"type":"string","label":"Order Date"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_year_month":{"name":"order_year_month","description":"Order year-month","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__sales__reporting__profitability"},"dimension":{"type":"string","label":"Order Year Month"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__sales__reporting__profitability"},"dimension":{"type":"string","label":"Order Year Month"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"type":"number","label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"type":"number","label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"revenue_per_day":{"name":"revenue_per_day","description":"Daily revenue per store","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__profitability"},"dimension":{"type":"string","label":"Revenue Per Day","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__profitability"},"dimension":{"type":"string","label":"Revenue Per Day","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"Foreign key to store","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"},"dimension":{"type":"string","label":"Store Id"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"},"dimension":{"type":"string","label":"Store Id"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_name":{"name":"store_name","description":"Store location name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"},"dimension":{"type":"string","label":"Store Name"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"},"dimension":{"type":"string","label":"Store Name"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_revenue_dollars":{"name":"total_revenue_dollars","description":"Total revenue in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__profitability"},"dimension":{"type":"string","label":"Total Revenue Dollars","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__profitability"},"dimension":{"type":"string","label":"Total Revenue Dollars","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_tax_collected_dollars":{"name":"total_tax_collected_dollars","description":"Total tax collected in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__profitability"},"dimension":{"type":"string","label":"Total Tax Collected Dollars","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__profitability"},"dimension":{"type":"string","label":"Total Tax Collected Dollars","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"sales","docs":{"show":true,"node_color":"#059669"},"patch_path":"jaffle_shop://models/marts/sales/reporting/mart__sales__reporting__profitability.yml","build_path":null,"unrendered_config":{"materialized":"view","group":"sales","tags":["json","lightdash-explore","mart"],"docs":{"node_color":"#059669","show":true},"contract":{"enforced":false}},"created_at":1777900097.9906409,"relation_name":"development.jaffle_shop_dev.mart__sales__reporting__profitability","raw_code":"{{\n config(\n materialized=\"view\"\n )\n}}\n\nWITH\n\tmart__sales__reporting__profitability AS (\n\t\tSELECT\n\t\t\tAVG(order_total_dollars) AS avg_order_value_dollars,\n\t\t\tCOUNT(*) AS order_count,\n\t\t\torder_date,\n\t\t\tDATE_TRUNC('month', order_date) AS order_year_month,\n\t\t\tsum(portal_source_count) AS portal_source_count,\n\t\t\tSUM(order_total_dollars) AS revenue_per_day,\n\t\t\tstore_id,\n\t\t\tstore_name,\n\t\t\tSUM(order_total_dollars) AS total_revenue_dollars,\n\t\t\tSUM(CAST(tax_paid_cents AS DECIMAL(10, 2)) / 100.0) AS total_tax_collected_dollars\n\t\tFROM\n\t\t\t{{ ref('int__sales__orders__enriched') }}\n\t\tGROUP BY\n\t\t\torder_date,\n\t\t\tDATE_TRUNC('month', order_date),\n\t\t\tstore_id,\n\t\t\tstore_name\n\t)\nSELECT\n\t*\nFROM\n\tmart__sales__reporting__profitability","doc_blocks":[],"language":"sql","refs":[{"name":"int__sales__orders__enriched","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.int__sales__orders__enriched"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics":{"database":"development","schema":"jaffle_shop_dev","name":"mart__analytics__dashboard__comprehensive_analytics","resource_type":"model","package_name":"jaffle_shop","path":"marts/analytics/dashboard/mart__analytics__dashboard__comprehensive_analytics.sql","original_file_path":"models/marts/analytics/dashboard/mart__analytics__dashboard__comprehensive_analytics.sql","unique_id":"model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics","fqn":["jaffle_shop","marts","analytics","dashboard","mart__analytics__dashboard__comprehensive_analytics"],"alias":"mart__analytics__dashboard__comprehensive_analytics","checksum":{"name":"sha256","checksum":"f632e9b79f77dd90892f2e965d5670ebb1d2c56d54de6185c71b086cc4673837"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["json","lightdash-explore","mart"],"meta":{},"group":"analytics","materialized":"view","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#059669"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","lightdash-explore","mart"],"description":"","columns":{"business_impact_score":{"name":"business_impact_score","description":"Business impact score based on cost efficiency (0-100)","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics"},"dimension":{"type":"string","label":"Business Impact Score","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics"},"dimension":{"type":"string","label":"Business Impact Score","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"cost_to_price_ratio":{"name":"cost_to_price_ratio","description":"Individual supply cost as ratio of selling price","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Cost To Price Ratio","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Cost To Price Ratio","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"is_perishable_supply":{"name":"is_perishable_supply","description":"Whether this supply is perishable","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Is Perishable Supply"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Is Perishable Supply"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"type":"number","label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"type":"number","label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_name":{"name":"product_name","description":"Product name, trimmed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"},"dimension":{"type":"string","label":"Product Name"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"},"dimension":{"type":"string","label":"Product Name"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_price_dollars":{"name":"product_price_dollars","description":"Product price in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"},"dimension":{"type":"string","label":"Product Price Dollars","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"},"dimension":{"type":"string","label":"Product Price Dollars","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_sku":{"name":"product_sku","description":"Product SKU identifier","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"},"dimension":{"type":"string","label":"Product Sku"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"},"dimension":{"type":"string","label":"Product Sku"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_type":{"name":"product_type","description":"Product type derived from SKU pattern","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"},"dimension":{"type":"string","label":"Product Type"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"},"dimension":{"type":"string","label":"Product Type"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"strategic_recommendation":{"name":"strategic_recommendation","description":"Strategic business recommendation","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics"},"dimension":{"type":"string","label":"Strategic Recommendation"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics"},"dimension":{"type":"string","label":"Strategic Recommendation"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_items_sold":{"name":"total_items_sold","description":"Total quantity of this product sold","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__products__analytics__product_popularity"},"dimension":{"type":"string","label":"Total Items Sold","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__products__analytics__product_popularity"},"dimension":{"type":"string","label":"Total Items Sold","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_orders":{"name":"total_orders","description":"Number of unique orders containing this product","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__products__analytics__product_popularity"},"dimension":{"type":"string","label":"Total Orders","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__products__analytics__product_popularity"},"dimension":{"type":"string","label":"Total Orders","hidden":true}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"analytics","docs":{"show":true,"node_color":"#059669"},"patch_path":"jaffle_shop://models/marts/analytics/dashboard/mart__analytics__dashboard__comprehensive_analytics.yml","build_path":null,"unrendered_config":{"materialized":"view","group":"analytics","tags":["json","lightdash-explore","mart"],"docs":{"node_color":"#059669","show":true},"contract":{"enforced":false}},"created_at":1777900097.992011,"relation_name":"development.jaffle_shop_dev.mart__analytics__dashboard__comprehensive_analytics","raw_code":"{{\n config(\n materialized=\"view\"\n )\n}}\n\nWITH\n\tmart__analytics__dashboard__comprehensive_analytics AS (\n\t\tSELECT\n\t\t\tCASE\n\t\t\t\tWHEN mart__products__reporting__cost_efficiency.cost_efficiency_category = 'Highly Efficient' THEN 100\n\t\t\t\tWHEN mart__products__reporting__cost_efficiency.cost_efficiency_category = 'Efficient' THEN 85\n\t\t\t\tWHEN mart__products__reporting__cost_efficiency.cost_efficiency_category = 'Moderate' THEN 70\n\t\t\t\tELSE 50\n\t\t\tEND AS business_impact_score,\n\t\t\tmart__products__reporting__cost_efficiency.cost_to_price_ratio,\n\t\t\tmart__products__reporting__cost_efficiency.is_perishable_supply,\n\t\t\tmart__products__reporting__cost_efficiency.portal_source_count,\n\t\t\tmart__products__reporting__cost_efficiency.product_name,\n\t\t\tmart__products__reporting__cost_efficiency.product_price_dollars,\n\t\t\tmart__products__reporting__menu_analytics.product_sku,\n\t\t\tmart__products__reporting__menu_analytics.product_type,\n\t\t\tCASE\n\t\t\t\tWHEN mart__products__reporting__cost_efficiency.cost_efficiency_category = 'Highly Efficient' THEN 'Promote & Expand'\n\t\t\t\tWHEN mart__products__reporting__cost_efficiency.cost_efficiency_category = 'Efficient' THEN 'Monitor Performance'\n\t\t\t\tWHEN mart__products__reporting__cost_efficiency.cost_efficiency_category = 'Moderate' THEN 'Optimize Costs'\n\t\t\t\tELSE 'Review Strategy'\n\t\t\tEND AS strategic_recommendation,\n\t\t\tmart__products__reporting__menu_analytics.total_items_sold,\n\t\t\tmart__products__reporting__menu_analytics.total_orders\n\t\tFROM\n\t\t\t{{ ref('mart__products__reporting__menu_analytics') }} mart__products__reporting__menu_analytics\n\t\t\tLEFT JOIN {{ ref('mart__products__reporting__cost_efficiency') }} mart__products__reporting__cost_efficiency ON mart__products__reporting__menu_analytics.product_sku = mart__products__reporting__cost_efficiency.product_sku\n\t)\nSELECT\n\t*\nFROM\n\tmart__analytics__dashboard__comprehensive_analytics","doc_blocks":[],"language":"sql","refs":[{"name":"mart__products__reporting__menu_analytics","package":null,"version":null},{"name":"mart__products__reporting__cost_efficiency","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.mart__products__reporting__menu_analytics","model.jaffle_shop.mart__products__reporting__cost_efficiency"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.int__customers__profiles__summary":{"database":"development","schema":"jaffle_shop_dev","name":"int__customers__profiles__summary","resource_type":"model","package_name":"jaffle_shop","path":"intermediate/customers/profiles/int__customers__profiles__summary.sql","original_file_path":"models/intermediate/customers/profiles/int__customers__profiles__summary.sql","unique_id":"model.jaffle_shop.int__customers__profiles__summary","fqn":["jaffle_shop","intermediate","customers","profiles","int__customers__profiles__summary"],"alias":"int__customers__profiles__summary","checksum":{"name":"sha256","checksum":"41250064d49f00fabea3a0c5ec7b604be27f73251cb9ef0a86f9950979f380a5"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["intermediate","json"],"meta":{},"group":"customers","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#DAA520"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["intermediate","json"],"description":"","columns":{"customer_first_name":{"name":"customer_first_name","description":"Customer first name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_id":{"name":"customer_id","description":"Unique identifier for each customer","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_last_name":{"name":"customer_last_name","description":"Customer last name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_name":{"name":"customer_name","description":"Customer full name, trimmed of whitespace","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_segment":{"name":"customer_segment","description":"Customer segment classification based on order count","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.int__customers__profiles__summary"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.int__customers__profiles__summary"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"has_last_name":{"name":"has_last_name","description":"Whether customer provided a last name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.int__customers__profiles__summary"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.int__customers__profiles__summary"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_orders":{"name":"total_orders","description":"Total number of orders placed by customer","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__customers__profiles__summary"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__customers__profiles__summary"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"customers","docs":{"show":true,"node_color":"#DAA520"},"patch_path":"jaffle_shop://models/intermediate/customers/profiles/int__customers__profiles__summary.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","group":"customers","tags":["intermediate","json"],"docs":{"node_color":"#DAA520","show":true},"contract":{"enforced":false}},"created_at":1777900098.0313191,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tint__customers__profiles__summary AS (\n\t\tSELECT\n\t\t\tstg__customers__profiles__clean.customer_first_name,\n\t\t\tstg__customers__profiles__clean.customer_id,\n\t\t\tstg__customers__profiles__clean.customer_last_name,\n\t\t\tstg__customers__profiles__clean.customer_name,\n\t\t\t{{ customer_segment() }} AS customer_segment,\n\t\t\tstg__customers__profiles__clean.customer_last_name IS NOT NULL AS has_last_name,\n\t\t\tsum(\n\t\t\t\tstg__customers__profiles__clean.portal_source_count\n\t\t\t) AS portal_source_count,\n\t\t\tCOUNT(stg__sales__orders__standardized.order_id) AS total_orders\n\t\tFROM\n\t\t\t{{ ref('stg__customers__profiles__clean') }} stg__customers__profiles__clean\n\t\t\tLEFT JOIN {{ ref('stg__sales__orders__standardized') }} stg__sales__orders__standardized ON stg__customers__profiles__clean.customer_id = stg__sales__orders__standardized.customer_id\n\t\tGROUP BY\n\t\t\tstg__customers__profiles__clean.customer_first_name,\n\t\t\tstg__customers__profiles__clean.customer_id,\n\t\t\tstg__customers__profiles__clean.customer_last_name,\n\t\t\tstg__customers__profiles__clean.customer_name\n\t)\nSELECT\n\t*\nFROM\n\tint__customers__profiles__summary","doc_blocks":[],"language":"sql","refs":[{"name":"stg__customers__profiles__clean","package":null,"version":null},{"name":"stg__sales__orders__standardized","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":["macro.jaffle_shop.customer_segment"],"nodes":["model.jaffle_shop.stg__customers__profiles__clean","model.jaffle_shop.stg__sales__orders__standardized"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.int__products__analytics__product_popularity":{"database":"development","schema":"jaffle_shop_dev","name":"int__products__analytics__product_popularity","resource_type":"model","package_name":"jaffle_shop","path":"intermediate/products/analytics/int__products__analytics__product_popularity.sql","original_file_path":"models/intermediate/products/analytics/int__products__analytics__product_popularity.sql","unique_id":"model.jaffle_shop.int__products__analytics__product_popularity","fqn":["jaffle_shop","intermediate","products","analytics","int__products__analytics__product_popularity"],"alias":"int__products__analytics__product_popularity","checksum":{"name":"sha256","checksum":"49fea0d39aaeabc54f366cd5764defac0160afc7e2574c87afef171435a4903f"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["intermediate","json"],"meta":{},"group":"products","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#DAA520"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["intermediate","json"],"description":"","columns":{"item_id":{"name":"item_id","description":"Unique identifier for each order item","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_sku":{"name":"product_sku","description":"Product SKU identifier","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_type":{"name":"product_type","description":"Product type derived from SKU pattern","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_items_sold":{"name":"total_items_sold","description":"Total quantity of this product sold","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__products__analytics__product_popularity"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__products__analytics__product_popularity"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_orders":{"name":"total_orders","description":"Number of unique orders containing this product","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__products__analytics__product_popularity"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__products__analytics__product_popularity"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"products","docs":{"show":true,"node_color":"#DAA520"},"patch_path":"jaffle_shop://models/intermediate/products/analytics/int__products__analytics__product_popularity.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","group":"products","tags":["intermediate","json"],"docs":{"node_color":"#DAA520","show":true},"contract":{"enforced":false}},"created_at":1777900098.0321128,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tint__products__analytics__product_popularity AS (\n\t\tSELECT\n\t\t\titem_id,\n\t\t\tsum(portal_source_count) AS portal_source_count,\n\t\t\tproduct_sku,\n\t\t\tproduct_type,\n\t\t\tCOUNT(*) AS total_items_sold,\n\t\t\tCOUNT(DISTINCT order_id) AS total_orders\n\t\tFROM\n\t\t\t{{ ref('stg__sales__items__order_details') }}\n\t\tGROUP BY\n\t\t\titem_id,\n\t\t\tproduct_sku,\n\t\t\tproduct_type\n\t)\nSELECT\n\t*\nFROM\n\tint__products__analytics__product_popularity","doc_blocks":[],"language":"sql","refs":[{"name":"stg__sales__items__order_details","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.stg__sales__items__order_details"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.int__sales__orders__enriched":{"database":"development","schema":"jaffle_shop_dev","name":"int__sales__orders__enriched","resource_type":"model","package_name":"jaffle_shop","path":"intermediate/sales/orders/int__sales__orders__enriched.sql","original_file_path":"models/intermediate/sales/orders/int__sales__orders__enriched.sql","unique_id":"model.jaffle_shop.int__sales__orders__enriched","fqn":["jaffle_shop","intermediate","sales","orders","int__sales__orders__enriched"],"alias":"int__sales__orders__enriched","checksum":{"name":"sha256","checksum":"8caf6828d75ffc47b0d22853b7c3ba56d8b52bc3143ca54ca12bc249c6d068eb"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["intermediate","json"],"meta":{},"group":"sales","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#DAA520"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["intermediate","json"],"description":"","columns":{"customer_first_name":{"name":"customer_first_name","description":"Customer first name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_id":{"name":"customer_id","description":"Foreign key to customer","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_name":{"name":"customer_name","description":"Customer full name, trimmed of whitespace","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_date":{"name":"order_date","description":"Date when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_id":{"name":"order_id","description":"Unique identifier for each order","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total_cents":{"name":"order_total_cents","description":"Total order amount in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total_dollars":{"name":"order_total_dollars","description":"Order total in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__sales__orders__enriched"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__sales__orders__enriched"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"ordered_at":{"name":"ordered_at","description":"Timestamp when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"Foreign key to store","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_name":{"name":"store_name","description":"Store location name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_tax_rate":{"name":"store_tax_rate","description":"Local tax rate for the store","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"subtotal_cents":{"name":"subtotal_cents","description":"Order subtotal in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"tax_paid_cents":{"name":"tax_paid_cents","description":"Tax amount paid in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"sales","docs":{"show":true,"node_color":"#DAA520"},"patch_path":"jaffle_shop://models/intermediate/sales/orders/int__sales__orders__enriched.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","group":"sales","tags":["intermediate","json"],"docs":{"node_color":"#DAA520","show":true},"contract":{"enforced":false}},"created_at":1777900098.033312,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tint__sales__orders__enriched AS (\n\t\tSELECT\n\t\t\tstg__customers__profiles__clean.customer_first_name,\n\t\t\tstg__sales__orders__standardized.customer_id,\n\t\t\tstg__customers__profiles__clean.customer_name,\n\t\t\tstg__sales__orders__standardized.order_date,\n\t\t\tstg__sales__orders__standardized.order_id,\n\t\t\tstg__sales__orders__standardized.order_total_cents,\n\t\t\tCAST(\n\t\t\t\tstg__sales__orders__standardized.order_total_cents AS DECIMAL(10, 2)\n\t\t\t) / 100.0 AS order_total_dollars,\n\t\t\tstg__sales__orders__standardized.ordered_at,\n\t\t\tstg__sales__orders__standardized.portal_source_count,\n\t\t\tstg__sales__orders__standardized.store_id,\n\t\t\tstg__sales__stores__locations.store_name,\n\t\t\tstg__sales__stores__locations.store_tax_rate,\n\t\t\tstg__sales__orders__standardized.subtotal_cents,\n\t\t\tstg__sales__orders__standardized.tax_paid_cents\n\t\tFROM\n\t\t\t{{ ref('stg__sales__orders__standardized') }} stg__sales__orders__standardized\n\t\t\tLEFT JOIN {{ ref('stg__customers__profiles__clean') }} stg__customers__profiles__clean ON stg__sales__orders__standardized.customer_id = stg__customers__profiles__clean.customer_id\n\t\t\tLEFT JOIN {{ ref('stg__sales__stores__locations') }} stg__sales__stores__locations ON stg__sales__orders__standardized.store_id = stg__sales__stores__locations.store_id\n\t)\nSELECT\n\t*\nFROM\n\tint__sales__orders__enriched","doc_blocks":[],"language":"sql","refs":[{"name":"stg__sales__orders__standardized","package":null,"version":null},{"name":"stg__customers__profiles__clean","package":null,"version":null},{"name":"stg__sales__stores__locations","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.stg__sales__orders__standardized","model.jaffle_shop.stg__customers__profiles__clean","model.jaffle_shop.stg__sales__stores__locations"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.int__sales__orders__regional_combined":{"database":"development","schema":"jaffle_shop_dev","name":"int__sales__orders__regional_combined","resource_type":"model","package_name":"jaffle_shop","path":"intermediate/sales/orders/int__sales__orders__regional_combined.sql","original_file_path":"models/intermediate/sales/orders/int__sales__orders__regional_combined.sql","unique_id":"model.jaffle_shop.int__sales__orders__regional_combined","fqn":["jaffle_shop","intermediate","sales","orders","int__sales__orders__regional_combined"],"alias":"int__sales__orders__regional_combined","checksum":{"name":"sha256","checksum":"b988eded0f7a248aabaa73ad50962b0a8b6db43ea229e52a98e8232c49dfeeb5"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["intermediate","json"],"meta":{},"group":"sales","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["intermediate","json"],"description":"Union of orders with regional classification for consolidated reporting across all stores","columns":{"customer_first_name":{"name":"customer_first_name","description":"Customer first name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_id":{"name":"customer_id","description":"Foreign key to customer","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_name":{"name":"customer_name","description":"Customer full name, trimmed of whitespace","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_date":{"name":"order_date","description":"Date when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_id":{"name":"order_id","description":"Unique identifier for each order","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total_cents":{"name":"order_total_cents","description":"Total order amount in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total_dollars":{"name":"order_total_dollars","description":"Order total in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__sales__orders__enriched"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__sales__orders__enriched"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"ordered_at":{"name":"ordered_at","description":"Timestamp when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"region":{"name":"region","description":"Geographic region classification","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.int__sales__orders__regional_combined"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.int__sales__orders__regional_combined"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"Foreign key to store","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_name":{"name":"store_name","description":"Store location name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_tax_rate":{"name":"store_tax_rate","description":"Local tax rate for the store","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"subtotal_cents":{"name":"subtotal_cents","description":"Order subtotal in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"tax_paid_cents":{"name":"tax_paid_cents","description":"Tax amount paid in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"sales","docs":{"show":true,"node_color":null},"patch_path":"jaffle_shop://models/intermediate/sales/orders/int__sales__orders__regional_combined.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","group":"sales","tags":["intermediate","json"],"docs":{"show":true},"contract":{"enforced":false}},"created_at":1777900098.034524,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tint__sales__orders__regional_combined AS (\n\t\tSELECT\n\t\t\tcustomer_first_name,\n\t\t\tcustomer_id,\n\t\t\tcustomer_name,\n\t\t\torder_date,\n\t\t\torder_id,\n\t\t\torder_total_cents,\n\t\t\torder_total_dollars,\n\t\t\tordered_at,\n\t\t\tportal_source_count,\n\t\t\tCASE\n\t\t\t\tWHEN store_name IN ('Philadelphia', 'Brooklyn') THEN 'East Coast'\n\t\t\t\tWHEN store_name IN ('San Francisco', 'Los Angeles') THEN 'West Coast'\n\t\t\t\tELSE 'Other'\n\t\t\tEND AS region,\n\t\t\tstore_id,\n\t\t\tstore_name,\n\t\t\tstore_tax_rate,\n\t\t\tsubtotal_cents,\n\t\t\ttax_paid_cents\n\t\tFROM\n\t\t\t{{ ref('int__sales__orders__enriched') }}\n\t\tUNION ALL\n\t\tSELECT\n\t\t\tcustomer_first_name,\n\t\t\tcustomer_id,\n\t\t\tcustomer_name,\n\t\t\torder_date,\n\t\t\torder_id,\n\t\t\torder_total_cents,\n\t\t\torder_total_dollars,\n\t\t\tordered_at,\n\t\t\tportal_source_count,\n\t\t\tCASE\n\t\t\t\tWHEN store_name IN ('Philadelphia', 'Brooklyn') THEN 'East Coast'\n\t\t\t\tWHEN store_name IN ('San Francisco', 'Los Angeles') THEN 'West Coast'\n\t\t\t\tELSE 'Other'\n\t\t\tEND AS region,\n\t\t\tstore_id,\n\t\t\tstore_name,\n\t\t\tstore_tax_rate,\n\t\t\tsubtotal_cents,\n\t\t\ttax_paid_cents\n\t\tFROM\n\t\t\t{{ ref('int__sales__orders__enriched') }}\n\t)\nSELECT\n\t*\nFROM\n\tint__sales__orders__regional_combined","doc_blocks":[],"language":"sql","refs":[{"name":"int__sales__orders__enriched","package":null,"version":null},{"name":"int__sales__orders__enriched","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.int__sales__orders__enriched"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.int__sales__analytics__rolling_30day":{"database":"development","schema":"jaffle_shop_dev","name":"int__sales__analytics__rolling_30day","resource_type":"model","package_name":"jaffle_shop","path":"intermediate/sales/analytics/int__sales__analytics__rolling_30day.sql","original_file_path":"models/intermediate/sales/analytics/int__sales__analytics__rolling_30day.sql","unique_id":"model.jaffle_shop.int__sales__analytics__rolling_30day","fqn":["jaffle_shop","intermediate","sales","analytics","int__sales__analytics__rolling_30day"],"alias":"int__sales__analytics__rolling_30day","checksum":{"name":"sha256","checksum":"78f7c85c824c65a077a0a270549607daa259992d89dbaf3c9845a746d4b4f806"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["intermediate","json"],"meta":{},"group":"sales","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["intermediate","json"],"description":"30-day rolling window analysis of sales metrics partitioned by store for trend analysis","columns":{"order_date":{"name":"order_date","description":"Date when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_id_count":{"name":"order_id_count","description":"Number of orders in the last 30 days","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"number","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total_dollars_sum":{"name":"order_total_dollars_sum","description":"Revenue metrics for the last 30 days (sum, min, max)","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__sales__orders__enriched"}},"data_type":"number","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__sales__orders__enriched"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total_dollars_min":{"name":"order_total_dollars_min","description":"Revenue metrics for the last 30 days (sum, min, max)","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__sales__orders__enriched"}},"data_type":"number","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__sales__orders__enriched"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total_dollars_max":{"name":"order_total_dollars_max","description":"Revenue metrics for the last 30 days (sum, min, max)","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__sales__orders__enriched"}},"data_type":"number","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__sales__orders__enriched"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"Foreign key to store","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_name":{"name":"store_name","description":"Store location name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_partition_daily":{"name":"portal_partition_daily","description":"Portal Partition Daily","meta":{"type":"dim"},"data_type":"date","constraints":[],"quote":null,"config":{"meta":{"type":"dim"},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"sales","docs":{"show":true,"node_color":null},"patch_path":"jaffle_shop://models/intermediate/sales/analytics/int__sales__analytics__rolling_30day.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","group":"sales","tags":["intermediate","json"],"docs":{"show":true},"contract":{"enforced":false}},"created_at":1777900098.0362828,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tint__sales__analytics__rolling_30day AS (\n\t\tSELECT\n\t\t\torder_date,\n\t\t\tcount(order_id) AS order_id_count,\n\t\t\tsum(order_total_dollars) AS order_total_dollars_sum,\n\t\t\tmin(order_total_dollars) AS order_total_dollars_min,\n\t\t\tmax(order_total_dollars) AS order_total_dollars_max,\n\t\t\tstore_id,\n\t\t\tstore_name,\n\t\t\t-- partition columns\n\t\t\t_ext_event_date AS portal_partition_daily\n\t\tFROM\n\t\t\t{{ _ext_event_dates_table() }}\n\t\t\tINNER JOIN {{ ref('int__sales__orders__enriched') }} ON portal_partition_daily <= _ext_event_date\n\t\t\tAND portal_partition_daily >= date_add('day', -30, _ext_event_date)\n\t\tGROUP BY\n\t\t\torder_date,\n\t\t\tstore_id,\n\t\t\tstore_name,\n\t\t\t_ext_event_date\n\t)\nSELECT\n\t*\nFROM\n\tint__sales__analytics__rolling_30day","doc_blocks":[],"language":"sql","refs":[{"name":"int__sales__orders__enriched","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":["macro.jaffle_shop._ext_event_dates_table"],"nodes":["model.jaffle_shop.int__sales__orders__enriched"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.int__sales__analytics__monthly_revenue":{"database":"development","schema":"jaffle_shop_dev","name":"int__sales__analytics__monthly_revenue","resource_type":"model","package_name":"jaffle_shop","path":"intermediate/sales/analytics/int__sales__analytics__monthly_revenue.sql","original_file_path":"models/intermediate/sales/analytics/int__sales__analytics__monthly_revenue.sql","unique_id":"model.jaffle_shop.int__sales__analytics__monthly_revenue","fqn":["jaffle_shop","intermediate","sales","analytics","int__sales__analytics__monthly_revenue"],"alias":"int__sales__analytics__monthly_revenue","checksum":{"name":"sha256","checksum":"cdf26dc4ad7142b7e0725fe845726a2bf53624200f27215c1ca466116e3d137c"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["intermediate","json"],"meta":{},"group":"sales","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["intermediate","json"],"description":"Monthly rollup of sales data aggregating revenue, orders, and customer metrics by store","columns":{"customer_first_name":{"name":"customer_first_name","description":"Customer first name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_id":{"name":"customer_id","description":"Foreign key to customer","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_name":{"name":"customer_name","description":"Customer full name, trimmed of whitespace","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"datetime":{"name":"datetime","description":"Datetime","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.int__sales__analytics__monthly_revenue"},"dimension":{"label":"Datetime","time_intervals":["MONTH","YEAR"]}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.int__sales__analytics__monthly_revenue"},"dimension":{"label":"Datetime","time_intervals":["MONTH","YEAR"]}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_date":{"name":"order_date","description":"Date when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_id":{"name":"order_id","description":"Unique identifier for each order","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"ordered_at":{"name":"ordered_at","description":"Timestamp when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"Foreign key to store","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_name":{"name":"store_name","description":"Store location name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"sales","docs":{"show":true,"node_color":null},"patch_path":"jaffle_shop://models/intermediate/sales/analytics/int__sales__analytics__monthly_revenue.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","group":"sales","tags":["intermediate","json"],"docs":{"show":true},"contract":{"enforced":false}},"created_at":1777900098.037596,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tint__sales__analytics__monthly_revenue AS (\n\t\tSELECT\n\t\t\tcustomer_first_name,\n\t\t\tcustomer_id,\n\t\t\tcustomer_name,\n\t\t\tdate_trunc('month', datetime) AS datetime,\n\t\t\torder_date,\n\t\t\torder_id,\n\t\t\tordered_at,\n\t\t\tsum(portal_source_count) AS portal_source_count,\n\t\t\tstore_id,\n\t\t\tstore_name\n\t\tFROM\n\t\t\t{{ ref('int__sales__orders__enriched') }}\n\t\tGROUP BY\n\t\t\tcustomer_first_name,\n\t\t\tcustomer_id,\n\t\t\tcustomer_name,\n\t\t\tdate_trunc('month', datetime),\n\t\t\torder_date,\n\t\t\torder_id,\n\t\t\tordered_at,\n\t\t\tstore_id,\n\t\t\tstore_name\n\t)\nSELECT\n\t*\nFROM\n\tint__sales__analytics__monthly_revenue","doc_blocks":[],"language":"sql","refs":[{"name":"int__sales__orders__enriched","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.int__sales__orders__enriched"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.int__supply_chain__supplies__cost_analysis":{"database":"development","schema":"jaffle_shop_dev","name":"int__supply_chain__supplies__cost_analysis","resource_type":"model","package_name":"jaffle_shop","path":"intermediate/supply_chain/supplies/int__supply_chain__supplies__cost_analysis.sql","original_file_path":"models/intermediate/supply_chain/supplies/int__supply_chain__supplies__cost_analysis.sql","unique_id":"model.jaffle_shop.int__supply_chain__supplies__cost_analysis","fqn":["jaffle_shop","intermediate","supply_chain","supplies","int__supply_chain__supplies__cost_analysis"],"alias":"int__supply_chain__supplies__cost_analysis","checksum":{"name":"sha256","checksum":"c569a2c4c33d074e0dcf3e5c65df4e583b8730580d837f2f8ccb474b59bedfca"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["intermediate","json"],"meta":{},"group":"supply_chain","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#DAA520"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["intermediate","json"],"description":"","columns":{"cost_cents":{"name":"cost_cents","description":"Supply cost in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"cost_dollars":{"name":"cost_dollars","description":"Supply cost in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"cost_tier":{"name":"cost_tier","description":"Supply cost tier classification","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.int__supply_chain__supplies__cost_analysis"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.int__supply_chain__supplies__cost_analysis"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"is_perishable":{"name":"is_perishable","description":"Boolean flag for perishable supplies","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_name":{"name":"product_name","description":"Product name, trimmed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_price_dollars":{"name":"product_price_dollars","description":"Product price in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_sku":{"name":"product_sku","description":"Associated product SKU","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_type":{"name":"product_type","description":"Product category (jaffle, beverage)","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"supply_category":{"name":"supply_category","description":"Supply category classification","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"supply_id":{"name":"supply_id","description":"Unique identifier for each supply item","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"supply_name":{"name":"supply_name","description":"Supply item name, trimmed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"supply_to_price_ratio":{"name":"supply_to_price_ratio","description":"Supply cost as percentage of product price","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__supply_chain__supplies__cost_analysis"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__supply_chain__supplies__cost_analysis"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"supply_chain","docs":{"show":true,"node_color":"#DAA520"},"patch_path":"jaffle_shop://models/intermediate/supply_chain/supplies/int__supply_chain__supplies__cost_analysis.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","group":"supply_chain","tags":["intermediate","json"],"docs":{"node_color":"#DAA520","show":true},"contract":{"enforced":false}},"created_at":1777900098.038665,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tint__supply_chain__supplies__cost_analysis AS (\n\t\tSELECT\n\t\t\tstg__supply_chain__supplies__inventory.cost_cents,\n\t\t\tstg__supply_chain__supplies__inventory.cost_dollars,\n\t\t\t{{ cost_tier() }} AS cost_tier,\n\t\t\tstg__supply_chain__supplies__inventory.is_perishable,\n\t\t\tstg__supply_chain__supplies__inventory.portal_source_count,\n\t\t\tstg__products__catalog__catalog.product_name,\n\t\t\tstg__products__catalog__catalog.product_price_dollars,\n\t\t\tstg__supply_chain__supplies__inventory.product_sku,\n\t\t\tstg__products__catalog__catalog.product_type,\n\t\t\tstg__supply_chain__supplies__inventory.supply_category,\n\t\t\tstg__supply_chain__supplies__inventory.supply_id,\n\t\t\tstg__supply_chain__supplies__inventory.supply_name,\n\t\t\t{{ supply_to_price_ratio() }} AS supply_to_price_ratio\n\t\tFROM\n\t\t\t{{ ref('stg__supply_chain__supplies__inventory') }} stg__supply_chain__supplies__inventory\n\t\t\tLEFT JOIN {{ ref('stg__products__catalog__catalog') }} stg__products__catalog__catalog ON stg__supply_chain__supplies__inventory.product_sku = stg__products__catalog__catalog.product_sku\n\t)\nSELECT\n\t*\nFROM\n\tint__supply_chain__supplies__cost_analysis","doc_blocks":[],"language":"sql","refs":[{"name":"stg__supply_chain__supplies__inventory","package":null,"version":null},{"name":"stg__products__catalog__catalog","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":["macro.jaffle_shop.cost_tier","macro.jaffle_shop.supply_to_price_ratio"],"nodes":["model.jaffle_shop.stg__supply_chain__supplies__inventory","model.jaffle_shop.stg__products__catalog__catalog"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"seed.jaffle_shop.raw_items":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_items","resource_type":"seed","package_name":"jaffle_shop","path":"raw_items.csv","original_file_path":"seeds/raw_items.csv","unique_id":"seed.jaffle_shop.raw_items","fqn":["jaffle_shop","raw_items"],"alias":"raw_items","checksum":{"name":"path","checksum":"seeds/raw_items.csv"},"config":{"enabled":true,"alias":null,"schema":"seeds","database":null,"tags":[],"meta":{},"group":null,"materialized":"seed","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"delimiter":",","quote_columns":false},"tags":[],"description":"","columns":{},"meta":{},"group":null,"docs":{"show":true,"node_color":null},"patch_path":null,"build_path":null,"unrendered_config":{"quote_columns":false,"schema":"seeds"},"created_at":1777900097.85508,"relation_name":"development.jaffle_shop_dev_seeds.raw_items","raw_code":"","doc_blocks":[],"root_path":"/path/to/dbt/project","depends_on":{"macros":[]}},"seed.jaffle_shop.raw_customers":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_customers","resource_type":"seed","package_name":"jaffle_shop","path":"raw_customers.csv","original_file_path":"seeds/raw_customers.csv","unique_id":"seed.jaffle_shop.raw_customers","fqn":["jaffle_shop","raw_customers"],"alias":"raw_customers","checksum":{"name":"sha256","checksum":"d91ca12deb29112b84ef9b56856fcb69645497bbca8315379dedf61b55b504b1"},"config":{"enabled":true,"alias":null,"schema":"seeds","database":null,"tags":[],"meta":{},"group":null,"materialized":"seed","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"delimiter":",","quote_columns":false},"tags":[],"description":"","columns":{},"meta":{},"group":null,"docs":{"show":true,"node_color":null},"patch_path":null,"build_path":null,"unrendered_config":{"quote_columns":false,"schema":"seeds"},"created_at":1777900097.856012,"relation_name":"development.jaffle_shop_dev_seeds.raw_customers","raw_code":"","doc_blocks":[],"root_path":"/path/to/dbt/project","depends_on":{"macros":[]}},"seed.jaffle_shop.raw_stores":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_stores","resource_type":"seed","package_name":"jaffle_shop","path":"raw_stores.csv","original_file_path":"seeds/raw_stores.csv","unique_id":"seed.jaffle_shop.raw_stores","fqn":["jaffle_shop","raw_stores"],"alias":"raw_stores","checksum":{"name":"sha256","checksum":"3766ca1319b55ea44a16296e24a5faefe26a182b85b0f5142c986482f9801ccc"},"config":{"enabled":true,"alias":null,"schema":"seeds","database":null,"tags":[],"meta":{},"group":null,"materialized":"seed","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"delimiter":",","quote_columns":false},"tags":[],"description":"","columns":{},"meta":{},"group":null,"docs":{"show":true,"node_color":null},"patch_path":null,"build_path":null,"unrendered_config":{"quote_columns":false,"schema":"seeds"},"created_at":1777900097.8566961,"relation_name":"development.jaffle_shop_dev_seeds.raw_stores","raw_code":"","doc_blocks":[],"root_path":"/path/to/dbt/project","depends_on":{"macros":[]}},"seed.jaffle_shop.raw_orders":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_orders","resource_type":"seed","package_name":"jaffle_shop","path":"raw_orders.csv","original_file_path":"seeds/raw_orders.csv","unique_id":"seed.jaffle_shop.raw_orders","fqn":["jaffle_shop","raw_orders"],"alias":"raw_orders","checksum":{"name":"path","checksum":"seeds/raw_orders.csv"},"config":{"enabled":true,"alias":null,"schema":"seeds","database":null,"tags":[],"meta":{},"group":null,"materialized":"seed","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"delimiter":",","quote_columns":false},"tags":[],"description":"","columns":{},"meta":{},"group":null,"docs":{"show":true,"node_color":null},"patch_path":null,"build_path":null,"unrendered_config":{"quote_columns":false,"schema":"seeds"},"created_at":1777900097.8573592,"relation_name":"development.jaffle_shop_dev_seeds.raw_orders","raw_code":"","doc_blocks":[],"root_path":"/path/to/dbt/project","depends_on":{"macros":[]}},"seed.jaffle_shop.raw_supplies":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_supplies","resource_type":"seed","package_name":"jaffle_shop","path":"raw_supplies.csv","original_file_path":"seeds/raw_supplies.csv","unique_id":"seed.jaffle_shop.raw_supplies","fqn":["jaffle_shop","raw_supplies"],"alias":"raw_supplies","checksum":{"name":"sha256","checksum":"da4dedefd0350e023054c208a20bda46ecc4b39e037b42be2ed4c39ed19ddf2d"},"config":{"enabled":true,"alias":null,"schema":"seeds","database":null,"tags":[],"meta":{},"group":null,"materialized":"seed","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"delimiter":",","quote_columns":false},"tags":[],"description":"","columns":{},"meta":{},"group":null,"docs":{"show":true,"node_color":null},"patch_path":null,"build_path":null,"unrendered_config":{"quote_columns":false,"schema":"seeds"},"created_at":1777900097.858015,"relation_name":"development.jaffle_shop_dev_seeds.raw_supplies","raw_code":"","doc_blocks":[],"root_path":"/path/to/dbt/project","depends_on":{"macros":[]}},"seed.jaffle_shop.raw_products":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_products","resource_type":"seed","package_name":"jaffle_shop","path":"raw_products.csv","original_file_path":"seeds/raw_products.csv","unique_id":"seed.jaffle_shop.raw_products","fqn":["jaffle_shop","raw_products"],"alias":"raw_products","checksum":{"name":"sha256","checksum":"a272e2f54aea0708c26ea3d8fb0cc6062196b68c8e47ab6197426c7cd3f841d8"},"config":{"enabled":true,"alias":null,"schema":"seeds","database":null,"tags":[],"meta":{},"group":null,"materialized":"seed","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"delimiter":",","quote_columns":false},"tags":[],"description":"","columns":{},"meta":{},"group":null,"docs":{"show":true,"node_color":null},"patch_path":null,"build_path":null,"unrendered_config":{"quote_columns":false,"schema":"seeds"},"created_at":1777900097.858969,"relation_name":"development.jaffle_shop_dev_seeds.raw_products","raw_code":"","doc_blocks":[],"root_path":"/path/to/dbt/project","depends_on":{"macros":[]}},"operation.jaffle_shop.jaffle_shop-on-run-start-0":{"database":"development","schema":"jaffle_shop_dev","name":"jaffle_shop-on-run-start-0","resource_type":"operation","package_name":"jaffle_shop","path":"hooks/jaffle_shop-on-run-start-0.sql","original_file_path":"./dbt_project.yml","unique_id":"operation.jaffle_shop.jaffle_shop-on-run-start-0","fqn":["jaffle_shop","hooks","jaffle_shop-on-run-start-0"],"alias":"jaffle_shop-on-run-start-0","checksum":{"name":"sha256","checksum":"f4d5f4fec0c794219b54d382a7559fbbf9dc34179f018f10c31c6973d773da01"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":[],"meta":{},"group":null,"materialized":"view","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null},"tags":["on-run-start"],"description":"","columns":{},"meta":{},"group":null,"docs":{"show":true,"node_color":null},"patch_path":null,"build_path":null,"unrendered_config":{},"created_at":1777900097.912394,"relation_name":null,"raw_code":"{{ log('Run started: ' ~ run_started_at, info=True) }}","doc_blocks":[],"language":"sql","refs":[],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":[]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"index":0},"operation.jaffle_shop.jaffle_shop-on-run-end-0":{"database":"development","schema":"jaffle_shop_dev","name":"jaffle_shop-on-run-end-0","resource_type":"operation","package_name":"jaffle_shop","path":"hooks/jaffle_shop-on-run-end-0.sql","original_file_path":"./dbt_project.yml","unique_id":"operation.jaffle_shop.jaffle_shop-on-run-end-0","fqn":["jaffle_shop","hooks","jaffle_shop-on-run-end-0"],"alias":"jaffle_shop-on-run-end-0","checksum":{"name":"sha256","checksum":"f4d5f4fec0c794219b54d382a7559fbbf9dc34179f018f10c31c6973d773da01"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":[],"meta":{},"group":null,"materialized":"view","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null},"tags":["on-run-end"],"description":"","columns":{},"meta":{},"group":null,"docs":{"show":true,"node_color":null},"patch_path":null,"build_path":null,"unrendered_config":{},"created_at":1777900097.916812,"relation_name":null,"raw_code":"{{ log('Run finished: ' ~ run_finished_at, info=True) }}","doc_blocks":[],"language":"sql","refs":[],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":[]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"index":0},"model.jaffle_shop.int__sales__orders__quality_checks":{"database":"development","schema":"jaffle_shop_dev","name":"int__sales__orders__quality_checks","resource_type":"model","package_name":"jaffle_shop","path":"intermediate/sales/orders/int__sales__orders__quality_checks.sql","original_file_path":"models/intermediate/sales/orders/int__sales__orders__quality_checks.sql","unique_id":"model.jaffle_shop.int__sales__orders__quality_checks","fqn":["jaffle_shop","intermediate","sales","orders","int__sales__orders__quality_checks"],"alias":"int__sales__orders__quality_checks","checksum":{"name":"sha256","checksum":"d0ffc5ccfc3c6fd77f16ed08874b92d413a30a2730aafc6ff4a26c1239cc08dd"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["intermediate","json"],"meta":{},"group":"sales","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["intermediate","json"],"description":"Demonstrates DJ test abstractions: data_tests with config, singular_tests, and unit_tests","columns":{"customer_first_name":{"name":"customer_first_name","description":"Customer first name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_id":{"name":"customer_id","description":"Foreign key to customer","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_name":{"name":"customer_name","description":"Customer full name, trimmed of whitespace","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_date":{"name":"order_date","description":"Date when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_id":{"name":"order_id","description":"Unique identifier for each order","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total_cents":{"name":"order_total_cents","description":"Total order amount in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total_dollars":{"name":"order_total_dollars","description":"Order total in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__sales__orders__enriched"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__sales__orders__enriched"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"ordered_at":{"name":"ordered_at","description":"Timestamp when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"Foreign key to store","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_name":{"name":"store_name","description":"Store location name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_tax_rate":{"name":"store_tax_rate","description":"Local tax rate for the store","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"subtotal_cents":{"name":"subtotal_cents","description":"Order subtotal in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"tax_paid_cents":{"name":"tax_paid_cents","description":"Tax amount paid in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"sales","docs":{"show":true,"node_color":null},"patch_path":"jaffle_shop://models/intermediate/sales/orders/int__sales__orders__quality_checks.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","group":"sales","tags":["intermediate","json"],"docs":{"show":true},"contract":{"enforced":false}},"created_at":1777900913.3752708,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tint__sales__orders__quality_checks AS (\n\t\tSELECT\n\t\t\tcustomer_first_name,\n\t\t\tcustomer_id,\n\t\t\tcustomer_name,\n\t\t\torder_date,\n\t\t\torder_id,\n\t\t\torder_total_cents,\n\t\t\torder_total_dollars,\n\t\t\tordered_at,\n\t\t\tportal_source_count,\n\t\t\tstore_id,\n\t\t\tstore_name,\n\t\t\tstore_tax_rate,\n\t\t\tsubtotal_cents,\n\t\t\ttax_paid_cents\n\t\tFROM\n\t\t\t{{ ref('int__sales__orders__enriched') }}\n\t)\nSELECT\n\t*\nFROM\n\tint__sales__orders__quality_checks","doc_blocks":[],"language":"sql","refs":[{"name":"int__sales__orders__enriched","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.int__sales__orders__enriched"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":["order_id"],"time_spine":null},"test.jaffle_shop.test_positive_order_totals":{"database":"development","schema":"jaffle_shop_dev_dbt_test__audit","name":"test_positive_order_totals","resource_type":"test","package_name":"jaffle_shop","path":"singular/test_positive_order_totals.sql","original_file_path":"tests/singular/test_positive_order_totals.sql","unique_id":"test.jaffle_shop.test_positive_order_totals","fqn":["jaffle_shop","singular","test_positive_order_totals"],"alias":"test_positive_order_totals","checksum":{"name":"sha256","checksum":"1ba41ea1ae0f4a02c5f1e5864cd3446b4f2f8d2ef87987325bd91a0410aa7729"},"config":{"enabled":true,"alias":null,"schema":"dbt_test__audit","database":null,"tags":["data_quality"],"meta":{},"group":null,"materialized":"test","severity":"error","store_failures":true,"store_failures_as":"table","where":null,"limit":null,"fail_calc":"count(*)","warn_if":"!= 0","error_if":"!= 0"},"tags":["data_quality"],"description":"","columns":{},"meta":{},"group":null,"docs":{"show":true,"node_color":null},"patch_path":null,"build_path":null,"unrendered_config":{"store_failures":true,"severity":"error","tags":["data_quality"]},"created_at":1777900913.323618,"relation_name":"development.jaffle_shop_dev_dbt_test__audit.test_positive_order_totals","raw_code":"/*\n * test_positive_order_totals\n * \n * Ensure all order totals are positive\n * \n * @dj-owner: int__sales__orders__quality_checks\n * @generated: DJ Framework - Do not edit this metadata line\n */\n\n{{ config(\n severity=\"error\",\n tags=[\"data_quality\"]\n) }}\n\nselect order_id, order_total_dollars from {{ ref('int__sales__orders__quality_checks') }} where order_total_dollars <= 0","doc_blocks":[],"language":"sql","refs":[{"name":"int__sales__orders__quality_checks","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.int__sales__orders__quality_checks"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null}},"test.jaffle_shop.unique_int__sales__orders__quality_checks_order_id.ca17cad549":{"database":"development","schema":"jaffle_shop_dev_dbt_test__audit","name":"unique_int__sales__orders__quality_checks_order_id","resource_type":"test","package_name":"jaffle_shop","path":"unique_int__sales__orders__quality_checks_order_id.sql","original_file_path":"models/intermediate/sales/orders/int__sales__orders__quality_checks.yml","unique_id":"test.jaffle_shop.unique_int__sales__orders__quality_checks_order_id.ca17cad549","fqn":["jaffle_shop","intermediate","sales","orders","unique_int__sales__orders__quality_checks_order_id"],"alias":"unique_int__sales__orders__quality_checks_order_id","checksum":{"name":"none","checksum":""},"config":{"enabled":true,"alias":null,"schema":"dbt_test__audit","database":null,"tags":["critical"],"meta":{},"group":null,"materialized":"test","severity":"error","store_failures":true,"store_failures_as":"table","where":null,"limit":null,"fail_calc":"count(*)","warn_if":"!= 0","error_if":"!= 0"},"tags":["critical"],"description":"","columns":{},"meta":{},"group":"sales","docs":{"show":true,"node_color":null},"patch_path":null,"build_path":null,"unrendered_config":{"store_failures":true,"severity":"error","tags":["critical"]},"created_at":1777900913.406522,"relation_name":"development.jaffle_shop_dev_dbt_test__audit.unique_int__sales__orders__quality_checks_order_id","raw_code":"{{ test_unique(**_dbt_generic_test_kwargs) }}{{ config(severity=\"error\",tags=['critical']) }}","doc_blocks":[],"language":"sql","refs":[{"name":"int__sales__orders__quality_checks","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":["macro.dbt.test_unique"],"nodes":["model.jaffle_shop.int__sales__orders__quality_checks"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"column_name":null,"file_key_name":"models.int__sales__orders__quality_checks","attached_node":"model.jaffle_shop.int__sales__orders__quality_checks","test_metadata":{"name":"unique","kwargs":{"column_name":"order_id","model":"{{ get_where_subquery(ref('int__sales__orders__quality_checks')) }}"},"namespace":null}}},"sources":{"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_customers":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_customers","resource_type":"source","package_name":"jaffle_shop","path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","original_file_path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","unique_id":"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_customers","fqn":["jaffle_shop","sources","development","development__jaffle_shop_dev_seeds","raw_customers"],"source_name":"development__jaffle_shop_dev_seeds","source_description":"","loader":"","identifier":"raw_customers","quoting":{"database":null,"schema":null,"identifier":null,"column":null},"loaded_at_field":null,"loaded_at_query":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"external":null,"description":"","columns":{"id":{"name":"id","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"name":{"name":"name","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"source_meta":{},"tags":[],"config":{"enabled":true,"event_time":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"patch_path":null,"unrendered_config":{"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"relation_name":"development.jaffle_shop_dev_seeds.raw_customers","created_at":1777900098.047325,"unrendered_database":"development","unrendered_schema":"jaffle_shop_dev_seeds","doc_blocks":[]},"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_items":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_items","resource_type":"source","package_name":"jaffle_shop","path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","original_file_path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","unique_id":"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_items","fqn":["jaffle_shop","sources","development","development__jaffle_shop_dev_seeds","raw_items"],"source_name":"development__jaffle_shop_dev_seeds","source_description":"","loader":"","identifier":"raw_items","quoting":{"database":null,"schema":null,"identifier":null,"column":null},"loaded_at_field":null,"loaded_at_query":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"external":null,"description":"","columns":{"id":{"name":"id","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_id":{"name":"order_id","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"sku":{"name":"sku","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"source_meta":{},"tags":[],"config":{"enabled":true,"event_time":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"patch_path":null,"unrendered_config":{"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"relation_name":"development.jaffle_shop_dev_seeds.raw_items","created_at":1777900098.0480871,"unrendered_database":"development","unrendered_schema":"jaffle_shop_dev_seeds","doc_blocks":[]},"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_orders":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_orders","resource_type":"source","package_name":"jaffle_shop","path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","original_file_path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","unique_id":"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_orders","fqn":["jaffle_shop","sources","development","development__jaffle_shop_dev_seeds","raw_orders"],"source_name":"development__jaffle_shop_dev_seeds","source_description":"","loader":"","identifier":"raw_orders","quoting":{"database":null,"schema":null,"identifier":null,"column":null},"loaded_at_field":null,"loaded_at_query":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"external":null,"description":"","columns":{"id":{"name":"id","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer":{"name":"customer","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"ordered_at":{"name":"ordered_at","description":"","meta":{},"data_type":"timestamp(3)","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"subtotal":{"name":"subtotal","description":"","meta":{},"data_type":"integer","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"tax_paid":{"name":"tax_paid","description":"","meta":{},"data_type":"integer","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total":{"name":"order_total","description":"","meta":{},"data_type":"integer","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"source_meta":{},"tags":[],"config":{"enabled":true,"event_time":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"patch_path":null,"unrendered_config":{"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"relation_name":"development.jaffle_shop_dev_seeds.raw_orders","created_at":1777900098.04828,"unrendered_database":"development","unrendered_schema":"jaffle_shop_dev_seeds","doc_blocks":[]},"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_products":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_products","resource_type":"source","package_name":"jaffle_shop","path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","original_file_path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","unique_id":"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_products","fqn":["jaffle_shop","sources","development","development__jaffle_shop_dev_seeds","raw_products"],"source_name":"development__jaffle_shop_dev_seeds","source_description":"","loader":"","identifier":"raw_products","quoting":{"database":null,"schema":null,"identifier":null,"column":null},"loaded_at_field":null,"loaded_at_query":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"external":null,"description":"","columns":{"sku":{"name":"sku","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"name":{"name":"name","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"type":{"name":"type","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"price":{"name":"price","description":"","meta":{},"data_type":"integer","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"description":{"name":"description","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"source_meta":{},"tags":[],"config":{"enabled":true,"event_time":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"patch_path":null,"unrendered_config":{"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"relation_name":"development.jaffle_shop_dev_seeds.raw_products","created_at":1777900098.048457,"unrendered_database":"development","unrendered_schema":"jaffle_shop_dev_seeds","doc_blocks":[]},"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_stores":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_stores","resource_type":"source","package_name":"jaffle_shop","path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","original_file_path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","unique_id":"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_stores","fqn":["jaffle_shop","sources","development","development__jaffle_shop_dev_seeds","raw_stores"],"source_name":"development__jaffle_shop_dev_seeds","source_description":"","loader":"","identifier":"raw_stores","quoting":{"database":null,"schema":null,"identifier":null,"column":null},"loaded_at_field":null,"loaded_at_query":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"external":null,"description":"","columns":{"id":{"name":"id","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"name":{"name":"name","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"opened_at":{"name":"opened_at","description":"","meta":{},"data_type":"timestamp(3)","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"tax_rate":{"name":"tax_rate","description":"","meta":{},"data_type":"double","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"source_meta":{},"tags":[],"config":{"enabled":true,"event_time":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"patch_path":null,"unrendered_config":{"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"relation_name":"development.jaffle_shop_dev_seeds.raw_stores","created_at":1777900098.04862,"unrendered_database":"development","unrendered_schema":"jaffle_shop_dev_seeds","doc_blocks":[]},"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_supplies":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_supplies","resource_type":"source","package_name":"jaffle_shop","path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","original_file_path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","unique_id":"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_supplies","fqn":["jaffle_shop","sources","development","development__jaffle_shop_dev_seeds","raw_supplies"],"source_name":"development__jaffle_shop_dev_seeds","source_description":"","loader":"","identifier":"raw_supplies","quoting":{"database":null,"schema":null,"identifier":null,"column":null},"loaded_at_field":null,"loaded_at_query":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"external":null,"description":"","columns":{"id":{"name":"id","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"name":{"name":"name","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"cost":{"name":"cost","description":"","meta":{},"data_type":"integer","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"perishable":{"name":"perishable","description":"","meta":{},"data_type":"boolean","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"sku":{"name":"sku","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"source_meta":{},"tags":[],"config":{"enabled":true,"event_time":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"patch_path":null,"unrendered_config":{"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"relation_name":"development.jaffle_shop_dev_seeds.raw_supplies","created_at":1777900098.048795,"unrendered_database":"development","unrendered_schema":"jaffle_shop_dev_seeds","doc_blocks":[]}},"docs":{"doc.dbt.__overview__":{"name":"__overview__","resource_type":"doc","package_name":"dbt","path":"overview.md","original_file_path":"docs/overview.md","unique_id":"doc.dbt.__overview__","block_contents":"### Welcome!\n\nWelcome to the auto-generated documentation for your dbt project!\n\n### Navigation\n\nYou can use the `Project` and `Database` navigation tabs on the left side of the window to explore the models\nin your project.\n\n#### Project Tab\nThe `Project` tab mirrors the directory structure of your dbt project. In this tab, you can see all of the\nmodels defined in your dbt project, as well as models imported from dbt packages.\n\n#### Database Tab\nThe `Database` tab also exposes your models, but in a format that looks more like a database explorer. This view\nshows relations (tables and views) grouped into database schemas. Note that ephemeral models are _not_ shown\nin this interface, as they do not exist in the database.\n\n### Graph Exploration\nYou can click the blue icon on the bottom-right corner of the page to view the lineage graph of your models.\n\nOn model pages, you'll see the immediate parents and children of the model you're exploring. By clicking the `Expand`\nbutton at the top-right of this lineage pane, you'll be able to see all of the models that are used to build,\nor are built from, the model you're exploring.\n\nOnce expanded, you'll be able to use the `--select` and `--exclude` model selection syntax to filter the\nmodels in the graph. For more information on model selection, check out the [dbt docs](https://docs.getdbt.com/docs/model-selection-syntax).\n\nNote that you can also right-click on models to interactively filter and explore the graph.\n\n---\n\n### More information\n\n- [What is dbt](https://docs.getdbt.com/docs/introduction)?\n- Read the [dbt viewpoint](https://docs.getdbt.com/docs/viewpoint)\n- [Installation](https://docs.getdbt.com/docs/installation)\n- Join the [dbt Community](https://www.getdbt.com/community/) for questions and discussion"}},"exposures":{},"metrics":{},"groups":{"group.jaffle_shop.sales":{"name":"sales","resource_type":"group","package_name":"jaffle_shop","path":"groups.yml","original_file_path":"models/groups.yml","unique_id":"group.jaffle_shop.sales","owner":{"email":"sales@example.com","name":"Sales Team"},"description":"Order processing, revenue tracking, profitability analysis, and sales performance metrics","config":{"meta":{}}},"group.jaffle_shop.products":{"name":"products","resource_type":"group","package_name":"jaffle_shop","path":"groups.yml","original_file_path":"models/groups.yml","unique_id":"group.jaffle_shop.products","owner":{"email":"product@example.com","name":"Product Team"},"description":"Product catalog management, menu analytics, cost efficiency analysis, and supply chain optimization","config":{"meta":{}}},"group.jaffle_shop.customers":{"name":"customers","resource_type":"group","package_name":"jaffle_shop","path":"groups.yml","original_file_path":"models/groups.yml","unique_id":"group.jaffle_shop.customers","owner":{"email":"customers@example.com","name":"Customer Team"},"description":"Customer profiles, behavior analysis, segmentation, and customer-focused dashboards","config":{"meta":{}}},"group.jaffle_shop.supply_chain":{"name":"supply_chain","resource_type":"group","package_name":"jaffle_shop","path":"groups.yml","original_file_path":"models/groups.yml","unique_id":"group.jaffle_shop.supply_chain","owner":{"email":"supply-chain@example.com","name":"Supply Chain Team"},"description":"Supply cost analysis, inventory management, and supplier performance tracking","config":{"meta":{}}},"group.jaffle_shop.analytics":{"name":"analytics","resource_type":"group","package_name":"jaffle_shop","path":"groups.yml","original_file_path":"models/groups.yml","unique_id":"group.jaffle_shop.analytics","owner":{"email":"analytics@example.com","name":"Analytics Team"},"description":"Cross-functional business intelligence, comprehensive analytics, and strategic insights across all business areas","config":{"meta":{}}}},"selectors":{},"disabled":{},"parent_map":{"model.jaffle_shop.stg__customers__profiles__clean":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_customers"],"model.jaffle_shop.stg__products__catalog__catalog":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_products"],"model.jaffle_shop.stg__sales__stores__locations":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_stores"],"model.jaffle_shop.stg__sales__orders__standardized":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_orders"],"model.jaffle_shop.stg__sales__items__order_details":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_items"],"model.jaffle_shop.stg__supply_chain__supplies__inventory":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_supplies"],"model.jaffle_shop.mart__customers__dashboard__analytics":["model.jaffle_shop.int__customers__profiles__summary"],"model.jaffle_shop.mart__products__reporting__cost_efficiency":["model.jaffle_shop.int__supply_chain__supplies__cost_analysis"],"model.jaffle_shop.mart__products__reporting__menu_analytics":["model.jaffle_shop.int__products__analytics__product_popularity"],"model.jaffle_shop.mart__sales__reporting__revenue":["model.jaffle_shop.int__sales__orders__enriched"],"model.jaffle_shop.mart__sales__reporting__profitability":["model.jaffle_shop.int__sales__orders__enriched"],"model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics":["model.jaffle_shop.mart__products__reporting__cost_efficiency","model.jaffle_shop.mart__products__reporting__menu_analytics"],"model.jaffle_shop.int__customers__profiles__summary":["model.jaffle_shop.stg__customers__profiles__clean","model.jaffle_shop.stg__sales__orders__standardized"],"model.jaffle_shop.int__products__analytics__product_popularity":["model.jaffle_shop.stg__sales__items__order_details"],"model.jaffle_shop.int__sales__orders__enriched":["model.jaffle_shop.stg__customers__profiles__clean","model.jaffle_shop.stg__sales__orders__standardized","model.jaffle_shop.stg__sales__stores__locations"],"model.jaffle_shop.int__sales__orders__regional_combined":["model.jaffle_shop.int__sales__orders__enriched"],"model.jaffle_shop.int__sales__analytics__rolling_30day":["model.jaffle_shop.int__sales__orders__enriched"],"model.jaffle_shop.int__sales__analytics__monthly_revenue":["model.jaffle_shop.int__sales__orders__enriched"],"model.jaffle_shop.int__supply_chain__supplies__cost_analysis":["model.jaffle_shop.stg__products__catalog__catalog","model.jaffle_shop.stg__supply_chain__supplies__inventory"],"seed.jaffle_shop.raw_items":[],"seed.jaffle_shop.raw_customers":[],"seed.jaffle_shop.raw_stores":[],"seed.jaffle_shop.raw_orders":[],"seed.jaffle_shop.raw_supplies":[],"seed.jaffle_shop.raw_products":[],"operation.jaffle_shop.jaffle_shop-on-run-start-0":[],"operation.jaffle_shop.jaffle_shop-on-run-end-0":[],"model.jaffle_shop.int__sales__orders__quality_checks":["model.jaffle_shop.int__sales__orders__enriched"],"test.jaffle_shop.test_positive_order_totals":["model.jaffle_shop.int__sales__orders__quality_checks"],"test.jaffle_shop.unique_int__sales__orders__quality_checks_order_id.ca17cad549":["model.jaffle_shop.int__sales__orders__quality_checks"],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_customers":[],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_items":[],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_orders":[],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_products":[],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_stores":[],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_supplies":[],"unit_test.jaffle_shop.int__sales__orders__quality_checks.test_order_logic":["model.jaffle_shop.int__sales__orders__quality_checks"]},"child_map":{"model.jaffle_shop.stg__customers__profiles__clean":["model.jaffle_shop.int__customers__profiles__summary","model.jaffle_shop.int__sales__orders__enriched"],"model.jaffle_shop.stg__products__catalog__catalog":["model.jaffle_shop.int__supply_chain__supplies__cost_analysis"],"model.jaffle_shop.stg__sales__stores__locations":["model.jaffle_shop.int__sales__orders__enriched"],"model.jaffle_shop.stg__sales__orders__standardized":["model.jaffle_shop.int__customers__profiles__summary","model.jaffle_shop.int__sales__orders__enriched"],"model.jaffle_shop.stg__sales__items__order_details":["model.jaffle_shop.int__products__analytics__product_popularity"],"model.jaffle_shop.stg__supply_chain__supplies__inventory":["model.jaffle_shop.int__supply_chain__supplies__cost_analysis"],"model.jaffle_shop.mart__customers__dashboard__analytics":[],"model.jaffle_shop.mart__products__reporting__cost_efficiency":["model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics"],"model.jaffle_shop.mart__products__reporting__menu_analytics":["model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics"],"model.jaffle_shop.mart__sales__reporting__revenue":[],"model.jaffle_shop.mart__sales__reporting__profitability":[],"model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics":[],"model.jaffle_shop.int__customers__profiles__summary":["model.jaffle_shop.mart__customers__dashboard__analytics"],"model.jaffle_shop.int__products__analytics__product_popularity":["model.jaffle_shop.mart__products__reporting__menu_analytics"],"model.jaffle_shop.int__sales__orders__enriched":["model.jaffle_shop.int__sales__analytics__monthly_revenue","model.jaffle_shop.int__sales__analytics__rolling_30day","model.jaffle_shop.int__sales__orders__quality_checks","model.jaffle_shop.int__sales__orders__regional_combined","model.jaffle_shop.mart__sales__reporting__profitability","model.jaffle_shop.mart__sales__reporting__revenue"],"model.jaffle_shop.int__sales__orders__regional_combined":[],"model.jaffle_shop.int__sales__analytics__rolling_30day":[],"model.jaffle_shop.int__sales__analytics__monthly_revenue":[],"model.jaffle_shop.int__supply_chain__supplies__cost_analysis":["model.jaffle_shop.mart__products__reporting__cost_efficiency"],"seed.jaffle_shop.raw_items":[],"seed.jaffle_shop.raw_customers":[],"seed.jaffle_shop.raw_stores":[],"seed.jaffle_shop.raw_orders":[],"seed.jaffle_shop.raw_supplies":[],"seed.jaffle_shop.raw_products":[],"operation.jaffle_shop.jaffle_shop-on-run-start-0":[],"operation.jaffle_shop.jaffle_shop-on-run-end-0":[],"model.jaffle_shop.int__sales__orders__quality_checks":["test.jaffle_shop.test_positive_order_totals","test.jaffle_shop.unique_int__sales__orders__quality_checks_order_id.ca17cad549","unit_test.jaffle_shop.int__sales__orders__quality_checks.test_order_logic"],"test.jaffle_shop.test_positive_order_totals":[],"test.jaffle_shop.unique_int__sales__orders__quality_checks_order_id.ca17cad549":[],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_customers":["model.jaffle_shop.stg__customers__profiles__clean"],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_items":["model.jaffle_shop.stg__sales__items__order_details"],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_orders":["model.jaffle_shop.stg__sales__orders__standardized"],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_products":["model.jaffle_shop.stg__products__catalog__catalog"],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_stores":["model.jaffle_shop.stg__sales__stores__locations"],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_supplies":["model.jaffle_shop.stg__supply_chain__supplies__inventory"],"unit_test.jaffle_shop.int__sales__orders__quality_checks.test_order_logic":[]},"group_map":{"sales":["model.jaffle_shop.stg__sales__stores__locations","model.jaffle_shop.stg__sales__orders__standardized","model.jaffle_shop.stg__sales__items__order_details","model.jaffle_shop.mart__sales__reporting__revenue","model.jaffle_shop.mart__sales__reporting__profitability","model.jaffle_shop.int__sales__orders__enriched","model.jaffle_shop.int__sales__orders__regional_combined","model.jaffle_shop.int__sales__analytics__rolling_30day","model.jaffle_shop.int__sales__analytics__monthly_revenue","model.jaffle_shop.int__sales__orders__quality_checks","test.jaffle_shop.unique_int__sales__orders__quality_checks_order_id.ca17cad549"],"products":["model.jaffle_shop.stg__products__catalog__catalog","model.jaffle_shop.mart__products__reporting__cost_efficiency","model.jaffle_shop.mart__products__reporting__menu_analytics","model.jaffle_shop.int__products__analytics__product_popularity"],"customers":["model.jaffle_shop.stg__customers__profiles__clean","model.jaffle_shop.mart__customers__dashboard__analytics","model.jaffle_shop.int__customers__profiles__summary"],"supply_chain":["model.jaffle_shop.stg__supply_chain__supplies__inventory","model.jaffle_shop.int__supply_chain__supplies__cost_analysis"],"analytics":["model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics"]},"saved_queries":{},"semantic_models":{},"unit_tests":{"unit_test.jaffle_shop.int__sales__orders__quality_checks.test_order_logic":{"model":"int__sales__orders__quality_checks","given":[{"input":"ref('int__sales__orders__enriched')","rows":[{"order_id":"1","order_total_dollars":"100"}],"format":"dict","fixture":null}],"expect":{"rows":[{"order_id":"1"}],"format":"dict","fixture":null},"name":"test_order_logic","resource_type":"unit_test","package_name":"jaffle_shop","path":"unit/int__sales__orders__quality_checks.unit.yml","original_file_path":"tests/unit/int__sales__orders__quality_checks.unit.yml","unique_id":"unit_test.jaffle_shop.int__sales__orders__quality_checks.test_order_logic","fqn":["jaffle_shop","unit","int__sales__orders__quality_checks","test_order_logic"],"description":"Test order processing","overrides":null,"depends_on":{"macros":[],"nodes":["model.jaffle_shop.int__sales__orders__quality_checks"]},"config":{"tags":[],"meta":{},"enabled":true},"checksum":"a9962bf1a87173e84124f1ec709d770a3d009dea1afaadc65e44a9b0fd82722a","schema":"jaffle_shop_dev","created_at":1777900913.346285,"versions":null,"version":null}}} \ No newline at end of file +{"metadata":{"dbt_schema_version":"https://schemas.getdbt.com/dbt/manifest/v12.json","dbt_version":"1.10.11","generated_at":"2026-10-27T06:52:14.460656Z","invocation_id":"9983cdf6-2d4b-42dc-87f6-2d285f419fc1","invocation_started_at":"2026-10-27T06:52:14.119761Z","env":{},"project_name":"jaffle_shop","project_id":"06e5b98c2db46f8a72cc4f66410e9b3b","user_id":null,"send_anonymous_usage_stats":false,"adapter_type":"trino","quoting":{"database":false,"schema":false,"identifier":false,"column":null}},"nodes":{"model.jaffle_shop.stg__customers__profiles__clean":{"database":"development","schema":"jaffle_shop_dev_staging","name":"stg__customers__profiles__clean","resource_type":"model","package_name":"jaffle_shop","path":"staging/customers/profiles/stg__customers__profiles__clean.sql","original_file_path":"models/staging/customers/profiles/stg__customers__profiles__clean.sql","unique_id":"model.jaffle_shop.stg__customers__profiles__clean","fqn":["jaffle_shop","staging","customers","profiles","stg__customers__profiles__clean"],"alias":"stg__customers__profiles__clean","checksum":{"name":"sha256","checksum":"287111d3952cfe726dbe9e981ee7081b346589275a6360c596261ca94f51a776"},"config":{"enabled":true,"alias":null,"schema":"staging","database":null,"tags":["json","staging"],"meta":{},"group":"customers","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#B6AB33"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","staging"],"description":"","columns":{"customer_first_name":{"name":"customer_first_name","description":"Customer first name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_id":{"name":"customer_id","description":"Unique identifier for each customer","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_last_name":{"name":"customer_last_name","description":"Customer last name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_name":{"name":"customer_name","description":"Customer full name, trimmed of whitespace","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"customers","docs":{"show":true,"node_color":"#B6AB33"},"patch_path":"jaffle_shop://models/staging/customers/profiles/stg__customers__profiles__clean.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","schema":"staging","group":"customers","tags":["json","staging"],"docs":{"node_color":"#B6AB33","show":true},"contract":{"enforced":false}},"created_at":1793083935.54366,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tstg__customers__profiles__clean AS (\n\t\tSELECT\n\t\t\tsplit(TRIM(name), ' ') [1] AS customer_first_name,\n\t\t\tid AS customer_id,\n\t\t\tCASE\n\t\t\t\tWHEN cardinality(split(TRIM(name), ' ')) > 1 THEN split(TRIM(name), ' ') [cardinality(split(TRIM(name), ' '))]\n\t\t\t\tELSE NULL\n\t\t\tEND AS customer_last_name,\n\t\t\tTRIM(name) AS customer_name,\n\t\t\t1 AS portal_source_count\n\t\tFROM\n\t\t\t{{ source('development__jaffle_shop_dev_seeds','raw_customers') }}\n\t)\nSELECT\n\t*\nFROM\n\tstg__customers__profiles__clean","doc_blocks":[],"language":"sql","refs":[],"sources":[["development__jaffle_shop_dev_seeds","raw_customers"]],"metrics":[],"depends_on":{"macros":[],"nodes":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_customers"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.stg__products__catalog__catalog":{"database":"development","schema":"jaffle_shop_dev_staging","name":"stg__products__catalog__catalog","resource_type":"model","package_name":"jaffle_shop","path":"staging/products/catalog/stg__products__catalog__catalog.sql","original_file_path":"models/staging/products/catalog/stg__products__catalog__catalog.sql","unique_id":"model.jaffle_shop.stg__products__catalog__catalog","fqn":["jaffle_shop","staging","products","catalog","stg__products__catalog__catalog"],"alias":"stg__products__catalog__catalog","checksum":{"name":"sha256","checksum":"9dc9de44d2bf73d9d9a961d348ae987846711bc1695ed792141e8aa513fd224a"},"config":{"enabled":true,"alias":null,"schema":"staging","database":null,"tags":["json","staging"],"meta":{},"group":"products","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#B6AB33"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","staging"],"description":"","columns":{"description":{"name":"description","description":"Product description","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"is_beverage":{"name":"is_beverage","description":"Boolean flag for beverage products","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"is_jaffle":{"name":"is_jaffle","description":"Boolean flag for jaffle products","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_name":{"name":"product_name","description":"Product name, trimmed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_price_cents":{"name":"product_price_cents","description":"Product price in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_price_dollars":{"name":"product_price_dollars","description":"Product price in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_sku":{"name":"product_sku","description":"Product SKU identifier","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_type":{"name":"product_type","description":"Product category (jaffle, beverage)","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"products","docs":{"show":true,"node_color":"#B6AB33"},"patch_path":"jaffle_shop://models/staging/products/catalog/stg__products__catalog__catalog.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","schema":"staging","group":"products","tags":["json","staging"],"docs":{"node_color":"#B6AB33","show":true},"contract":{"enforced":false}},"created_at":1793083935.5463219,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tstg__products__catalog__catalog AS (\n\t\tSELECT\n\t\t\tTRIM(description) AS description,\n\t\t\tLOWER(TRIM(TYPE)) = 'beverage' AS is_beverage,\n\t\t\tLOWER(TRIM(TYPE)) = 'jaffle' AS is_jaffle,\n\t\t\t1 AS portal_source_count,\n\t\t\tTRIM(name) AS product_name,\n\t\t\tprice AS product_price_cents,\n\t\t\tCAST(price AS DECIMAL(10, 2)) / 100.0 AS product_price_dollars,\n\t\t\tsku AS product_sku,\n\t\t\tTRIM(TYPE) AS product_type\n\t\tFROM\n\t\t\t{{ source('development__jaffle_shop_dev_seeds','raw_products') }}\n\t)\nSELECT\n\t*\nFROM\n\tstg__products__catalog__catalog","doc_blocks":[],"language":"sql","refs":[],"sources":[["development__jaffle_shop_dev_seeds","raw_products"]],"metrics":[],"depends_on":{"macros":[],"nodes":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_products"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.stg__sales__stores__locations":{"database":"development","schema":"jaffle_shop_dev_staging","name":"stg__sales__stores__locations","resource_type":"model","package_name":"jaffle_shop","path":"staging/sales/stores/stg__sales__stores__locations.sql","original_file_path":"models/staging/sales/stores/stg__sales__stores__locations.sql","unique_id":"model.jaffle_shop.stg__sales__stores__locations","fqn":["jaffle_shop","staging","sales","stores","stg__sales__stores__locations"],"alias":"stg__sales__stores__locations","checksum":{"name":"sha256","checksum":"f540771873516a9be7d0c9255e6cb666d633e2aeceb3236f8f3a00dd7dbc5b40"},"config":{"enabled":true,"alias":null,"schema":"staging","database":null,"tags":["json","staging"],"meta":{},"group":"sales","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#B6AB33"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","staging"],"description":"","columns":{"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"Unique identifier for each store","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_name":{"name":"store_name","description":"Store location name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_opened_at":{"name":"store_opened_at","description":"Timestamp when store opened","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_opened_date":{"name":"store_opened_date","description":"Date when store opened","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_tax_rate":{"name":"store_tax_rate","description":"Local tax rate for the store","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_tax_rate_percent":{"name":"store_tax_rate_percent","description":"Tax rate as percentage","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"sales","docs":{"show":true,"node_color":"#B6AB33"},"patch_path":"jaffle_shop://models/staging/sales/stores/stg__sales__stores__locations.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","schema":"staging","group":"sales","tags":["json","staging"],"docs":{"node_color":"#B6AB33","show":true},"contract":{"enforced":false}},"created_at":1793083935.548405,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tstg__sales__stores__locations AS (\n\t\tSELECT\n\t\t\t1 AS portal_source_count,\n\t\t\tid AS store_id,\n\t\t\tTRIM(name) AS store_name,\n\t\t\tCAST(opened_at AS TIMESTAMP) AS store_opened_at,\n\t\t\tDATE(CAST(opened_at AS TIMESTAMP)) AS store_opened_date,\n\t\t\ttax_rate AS store_tax_rate,\n\t\t\ttax_rate * 100 AS store_tax_rate_percent\n\t\tFROM\n\t\t\t{{ source('development__jaffle_shop_dev_seeds','raw_stores') }}\n\t)\nSELECT\n\t*\nFROM\n\tstg__sales__stores__locations","doc_blocks":[],"language":"sql","refs":[],"sources":[["development__jaffle_shop_dev_seeds","raw_stores"]],"metrics":[],"depends_on":{"macros":[],"nodes":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_stores"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.stg__sales__orders__standardized":{"database":"development","schema":"jaffle_shop_dev_staging","name":"stg__sales__orders__standardized","resource_type":"model","package_name":"jaffle_shop","path":"staging/sales/orders/stg__sales__orders__standardized.sql","original_file_path":"models/staging/sales/orders/stg__sales__orders__standardized.sql","unique_id":"model.jaffle_shop.stg__sales__orders__standardized","fqn":["jaffle_shop","staging","sales","orders","stg__sales__orders__standardized"],"alias":"stg__sales__orders__standardized","checksum":{"name":"sha256","checksum":"c6f5fb75f6eb8b31fb5d26838e257c14b2330b60f5b4b289a0a16a92330d58f7"},"config":{"enabled":true,"alias":null,"schema":"staging","database":null,"tags":["json","staging"],"meta":{},"group":"sales","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#B6AB33"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","staging"],"description":"","columns":{"customer_id":{"name":"customer_id","description":"Foreign key to customer","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_date":{"name":"order_date","description":"Date when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_id":{"name":"order_id","description":"Unique identifier for each order","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total_cents":{"name":"order_total_cents","description":"Total order amount in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"ordered_at":{"name":"ordered_at","description":"Timestamp when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"Foreign key to store","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"subtotal_cents":{"name":"subtotal_cents","description":"Order subtotal in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"tax_paid_cents":{"name":"tax_paid_cents","description":"Tax amount paid in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"sales","docs":{"show":true,"node_color":"#B6AB33"},"patch_path":"jaffle_shop://models/staging/sales/orders/stg__sales__orders__standardized.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","schema":"staging","group":"sales","tags":["json","staging"],"docs":{"node_color":"#B6AB33","show":true},"contract":{"enforced":false}},"created_at":1793083935.550425,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tstg__sales__orders__standardized AS (\n\t\tSELECT\n\t\t\tcustomer AS customer_id,\n\t\t\tDATE(CAST(ordered_at AS TIMESTAMP)) AS order_date,\n\t\t\tid AS order_id,\n\t\t\torder_total AS order_total_cents,\n\t\t\tCAST(ordered_at AS TIMESTAMP) AS ordered_at,\n\t\t\t1 AS portal_source_count,\n\t\t\tstore_id AS store_id,\n\t\t\tsubtotal AS subtotal_cents,\n\t\t\ttax_paid AS tax_paid_cents\n\t\tFROM\n\t\t\t{{ source('development__jaffle_shop_dev_seeds','raw_orders') }}\n\t)\nSELECT\n\t*\nFROM\n\tstg__sales__orders__standardized","doc_blocks":[],"language":"sql","refs":[],"sources":[["development__jaffle_shop_dev_seeds","raw_orders"]],"metrics":[],"depends_on":{"macros":[],"nodes":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_orders"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.stg__sales__items__order_details":{"database":"development","schema":"jaffle_shop_dev_staging","name":"stg__sales__items__order_details","resource_type":"model","package_name":"jaffle_shop","path":"staging/sales/items/stg__sales__items__order_details.sql","original_file_path":"models/staging/sales/items/stg__sales__items__order_details.sql","unique_id":"model.jaffle_shop.stg__sales__items__order_details","fqn":["jaffle_shop","staging","sales","items","stg__sales__items__order_details"],"alias":"stg__sales__items__order_details","checksum":{"name":"sha256","checksum":"3e1cb4978cc09f8884d2012ddd69b41ff08fda10376e04b342723e7c8dc4641a"},"config":{"enabled":true,"alias":null,"schema":"staging","database":null,"tags":["json","staging"],"meta":{},"group":"sales","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#B6AB33"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","staging"],"description":"","columns":{"is_beverage_item":{"name":"is_beverage_item","description":"Boolean flag for beverage items","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"is_jaffle_item":{"name":"is_jaffle_item","description":"Boolean flag for jaffle items","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"item_id":{"name":"item_id","description":"Unique identifier for each order item","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_id":{"name":"order_id","description":"Foreign key to orders table","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_sku":{"name":"product_sku","description":"Product SKU identifier","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_type":{"name":"product_type","description":"Product type derived from SKU pattern","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"sales","docs":{"show":true,"node_color":"#B6AB33"},"patch_path":"jaffle_shop://models/staging/sales/items/stg__sales__items__order_details.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","schema":"staging","group":"sales","tags":["json","staging"],"docs":{"node_color":"#B6AB33","show":true},"contract":{"enforced":false}},"created_at":1793083935.552104,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tstg__sales__items__order_details AS (\n\t\tSELECT\n\t\t\tsku LIKE 'BEV-%' AS is_beverage_item,\n\t\t\tsku LIKE 'JAF-%' AS is_jaffle_item,\n\t\t\tid AS item_id,\n\t\t\torder_id AS order_id,\n\t\t\t1 AS portal_source_count,\n\t\t\tsku AS product_sku,\n\t\t\tCASE\n\t\t\t\tWHEN sku LIKE 'JAF-%' THEN 'jaffle'\n\t\t\t\tWHEN sku LIKE 'BEV-%' THEN 'beverage'\n\t\t\t\tELSE 'unknown'\n\t\t\tEND AS product_type\n\t\tFROM\n\t\t\t{{ source('development__jaffle_shop_dev_seeds','raw_items') }}\n\t)\nSELECT\n\t*\nFROM\n\tstg__sales__items__order_details","doc_blocks":[],"language":"sql","refs":[],"sources":[["development__jaffle_shop_dev_seeds","raw_items"]],"metrics":[],"depends_on":{"macros":[],"nodes":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_items"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.stg__supply_chain__supplies__inventory":{"database":"development","schema":"jaffle_shop_dev_staging","name":"stg__supply_chain__supplies__inventory","resource_type":"model","package_name":"jaffle_shop","path":"staging/supply_chain/supplies/stg__supply_chain__supplies__inventory.sql","original_file_path":"models/staging/supply_chain/supplies/stg__supply_chain__supplies__inventory.sql","unique_id":"model.jaffle_shop.stg__supply_chain__supplies__inventory","fqn":["jaffle_shop","staging","supply_chain","supplies","stg__supply_chain__supplies__inventory"],"alias":"stg__supply_chain__supplies__inventory","checksum":{"name":"sha256","checksum":"1809b8f0c6f71c29c5300ad12fdacfec24bc22280612dcd2a8ebadc7d3c6f5d6"},"config":{"enabled":true,"alias":null,"schema":"staging","database":null,"tags":["json","staging"],"meta":{},"group":"supply_chain","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#B6AB33"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","staging"],"description":"","columns":{"cost_cents":{"name":"cost_cents","description":"Supply cost in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"cost_dollars":{"name":"cost_dollars","description":"Supply cost in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"is_perishable":{"name":"is_perishable","description":"Boolean flag for perishable supplies","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_sku":{"name":"product_sku","description":"Associated product SKU","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"supply_category":{"name":"supply_category","description":"Supply category classification","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"supply_id":{"name":"supply_id","description":"Unique identifier for each supply item","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"supply_name":{"name":"supply_name","description":"Supply item name, trimmed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"supply_chain","docs":{"show":true,"node_color":"#B6AB33"},"patch_path":"jaffle_shop://models/staging/supply_chain/supplies/stg__supply_chain__supplies__inventory.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","schema":"staging","group":"supply_chain","tags":["json","staging"],"docs":{"node_color":"#B6AB33","show":true},"contract":{"enforced":false}},"created_at":1793083935.5540779,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tstg__supply_chain__supplies__inventory AS (\n\t\tSELECT\n\t\t\tcost AS cost_cents,\n\t\t\tCAST(cost AS DECIMAL(10, 2)) / 100.0 AS cost_dollars,\n\t\t\tCASE\n\t\t\t\tWHEN perishable = TRUE THEN TRUE\n\t\t\t\tELSE FALSE\n\t\t\tEND AS is_perishable,\n\t\t\t1 AS portal_source_count,\n\t\t\tsku AS product_sku,\n\t\t\tCASE\n\t\t\t\tWHEN LOWER(name) LIKE '%cutlery%'\n\t\t\t\tOR LOWER(name) LIKE '%fork%'\n\t\t\t\tOR LOWER(name) LIKE '%knife%' THEN 'utensils'\n\t\t\t\tWHEN LOWER(name) LIKE '%napkin%'\n\t\t\t\tOR LOWER(name) LIKE '%boat%' THEN 'packaging'\n\t\t\t\tWHEN perishable = TRUE THEN 'ingredients'\n\t\t\t\tELSE 'other'\n\t\t\tEND AS supply_category,\n\t\t\tid AS supply_id,\n\t\t\tTRIM(name) AS supply_name\n\t\tFROM\n\t\t\t{{ source('development__jaffle_shop_dev_seeds','raw_supplies') }}\n\t)\nSELECT\n\t*\nFROM\n\tstg__supply_chain__supplies__inventory","doc_blocks":[],"language":"sql","refs":[],"sources":[["development__jaffle_shop_dev_seeds","raw_supplies"]],"metrics":[],"depends_on":{"macros":[],"nodes":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_supplies"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.mart__customers__dashboard__analytics":{"database":"development","schema":"jaffle_shop_dev","name":"mart__customers__dashboard__analytics","resource_type":"model","package_name":"jaffle_shop","path":"marts/customers/dashboard/mart__customers__dashboard__analytics.sql","original_file_path":"models/marts/customers/dashboard/mart__customers__dashboard__analytics.sql","unique_id":"model.jaffle_shop.mart__customers__dashboard__analytics","fqn":["jaffle_shop","marts","customers","dashboard","mart__customers__dashboard__analytics"],"alias":"mart__customers__dashboard__analytics","checksum":{"name":"sha256","checksum":"d74eb1171643e36fdf8303e9d0ede6fde081029d1b3378551e46c2b5d261f72a"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["json","lightdash-explore","mart"],"meta":{},"group":"customers","materialized":"view","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#059669"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","lightdash-explore","mart"],"description":"","columns":{"customer_first_name":{"name":"customer_first_name","description":"Customer first name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"},"dimension":{"type":"string","label":"Customer First Name"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_id":{"name":"customer_id","description":"Unique identifier for each customer","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"},"dimension":{"type":"string","label":"Customer Id"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_last_name":{"name":"customer_last_name","description":"Customer last name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"},"dimension":{"type":"string","label":"Customer Last Name"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_name":{"name":"customer_name","description":"Customer full name, trimmed of whitespace","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"},"dimension":{"type":"string","label":"Customer Name"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_segment":{"name":"customer_segment","description":"Customer segment classification based on order count","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__customers__dashboard__analytics"},"dimension":{"type":"string","label":"Customer Segment"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"has_last_name":{"name":"has_last_name","description":"Whether customer provided a last name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.int__customers__profiles__summary"},"dimension":{"type":"string","label":"Has Last Name"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"type":"number","label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_orders":{"name":"total_orders","description":"Total number of orders placed by customer","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__customers__profiles__summary"},"dimension":{"type":"string","label":"Total Orders","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"customers","docs":{"show":true,"node_color":"#059669"},"patch_path":"jaffle_shop://models/marts/customers/dashboard/mart__customers__dashboard__analytics.yml","build_path":null,"unrendered_config":{"materialized":"view","group":"customers","tags":["json","lightdash-explore","mart"],"docs":{"node_color":"#059669","show":true},"contract":{"enforced":false}},"created_at":1793083935.557434,"relation_name":"development.jaffle_shop_dev.mart__customers__dashboard__analytics","raw_code":"{{\n config(\n materialized=\"view\"\n )\n}}\n\nWITH\n\tmart__customers__dashboard__analytics AS (\n\t\tSELECT\n\t\t\tcustomer_first_name,\n\t\t\tcustomer_id,\n\t\t\tcustomer_last_name,\n\t\t\tcustomer_name,\n\t\t\tCASE\n\t\t\t\tWHEN total_orders >= 10 THEN 'VIP'\n\t\t\t\tWHEN total_orders >= 3 THEN 'Regular'\n\t\t\t\tELSE 'New'\n\t\t\tEND AS customer_segment,\n\t\t\thas_last_name,\n\t\t\tportal_source_count,\n\t\t\ttotal_orders\n\t\tFROM\n\t\t\t{{ ref('int__customers__profiles__summary') }}\n\t)\nSELECT\n\t*\nFROM\n\tmart__customers__dashboard__analytics","doc_blocks":[],"language":"sql","refs":[{"name":"int__customers__profiles__summary","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.int__customers__profiles__summary"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.mart__products__reporting__cost_efficiency":{"database":"development","schema":"jaffle_shop_dev","name":"mart__products__reporting__cost_efficiency","resource_type":"model","package_name":"jaffle_shop","path":"marts/products/reporting/mart__products__reporting__cost_efficiency.sql","original_file_path":"models/marts/products/reporting/mart__products__reporting__cost_efficiency.sql","unique_id":"model.jaffle_shop.mart__products__reporting__cost_efficiency","fqn":["jaffle_shop","marts","products","reporting","mart__products__reporting__cost_efficiency"],"alias":"mart__products__reporting__cost_efficiency","checksum":{"name":"sha256","checksum":"d36e0bd5cc45bd1e8d9636dfaa9b1fa96cc06b5612eaba5f658f3ddbcb9e3b49"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["json","lightdash-explore","mart"],"meta":{},"group":"products","materialized":"view","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#059669"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","lightdash-explore","mart"],"description":"","columns":{"cost_efficiency_category":{"name":"cost_efficiency_category","description":"Cost efficiency classification","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Cost Efficiency Category"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"cost_to_price_ratio":{"name":"cost_to_price_ratio","description":"Individual supply cost as ratio of selling price","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Cost To Price Ratio","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"is_perishable_supply":{"name":"is_perishable_supply","description":"Whether this supply is perishable","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Is Perishable Supply"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"perishable_risk_level":{"name":"perishable_risk_level","description":"Risk level based on perishable supplies","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Perishable Risk Level"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"type":"number","label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_name":{"name":"product_name","description":"Product name, trimmed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"},"dimension":{"type":"string","label":"Product Name"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_price_dollars":{"name":"product_price_dollars","description":"Product price in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"},"dimension":{"type":"string","label":"Product Price Dollars","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_sku":{"name":"product_sku","description":"Associated product SKU","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"},"dimension":{"type":"string","label":"Product Sku"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_type":{"name":"product_type","description":"Product category (jaffle, beverage)","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"},"dimension":{"type":"string","label":"Product Type"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"supply_cost_dollars":{"name":"supply_cost_dollars","description":"Individual supply cost in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Supply Cost Dollars","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"products","docs":{"show":true,"node_color":"#059669"},"patch_path":"jaffle_shop://models/marts/products/reporting/mart__products__reporting__cost_efficiency.yml","build_path":null,"unrendered_config":{"materialized":"view","group":"products","tags":["json","lightdash-explore","mart"],"docs":{"node_color":"#059669","show":true},"contract":{"enforced":false}},"created_at":1793083935.5605912,"relation_name":"development.jaffle_shop_dev.mart__products__reporting__cost_efficiency","raw_code":"{{\n config(\n materialized=\"view\"\n )\n}}\n\nWITH\n\tmart__products__reporting__cost_efficiency AS (\n\t\tSELECT\n\t\t\tCASE\n\t\t\t\tWHEN cost_dollars / product_price_dollars <= 0.30 THEN 'Highly Efficient'\n\t\t\t\tWHEN cost_dollars / product_price_dollars <= 0.50 THEN 'Efficient'\n\t\t\t\tWHEN cost_dollars / product_price_dollars <= 0.70 THEN 'Moderate'\n\t\t\t\tELSE 'Low Efficiency'\n\t\t\tEND AS cost_efficiency_category,\n\t\t\tCASE\n\t\t\t\tWHEN product_price_dollars > 0 THEN cost_dollars / product_price_dollars\n\t\t\t\tELSE NULL\n\t\t\tEND AS cost_to_price_ratio,\n\t\t\tis_perishable AS is_perishable_supply,\n\t\t\tCASE\n\t\t\t\tWHEN is_perishable THEN 'High Risk'\n\t\t\t\tELSE 'Low Risk'\n\t\t\tEND AS perishable_risk_level,\n\t\t\tportal_source_count,\n\t\t\tproduct_name,\n\t\t\tproduct_price_dollars,\n\t\t\tproduct_sku,\n\t\t\tproduct_type,\n\t\t\tcost_dollars AS supply_cost_dollars\n\t\tFROM\n\t\t\t{{ ref('int__supply_chain__supplies__cost_analysis') }}\n\t)\nSELECT\n\t*\nFROM\n\tmart__products__reporting__cost_efficiency","doc_blocks":[],"language":"sql","refs":[{"name":"int__supply_chain__supplies__cost_analysis","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.int__supply_chain__supplies__cost_analysis"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.mart__products__reporting__menu_analytics":{"database":"development","schema":"jaffle_shop_dev","name":"mart__products__reporting__menu_analytics","resource_type":"model","package_name":"jaffle_shop","path":"marts/products/reporting/mart__products__reporting__menu_analytics.sql","original_file_path":"models/marts/products/reporting/mart__products__reporting__menu_analytics.sql","unique_id":"model.jaffle_shop.mart__products__reporting__menu_analytics","fqn":["jaffle_shop","marts","products","reporting","mart__products__reporting__menu_analytics"],"alias":"mart__products__reporting__menu_analytics","checksum":{"name":"sha256","checksum":"a0f496985a432632cb87c7fbac4a525d8c9916d1ca1d201849f517601fb4e0fc"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["json","lightdash-explore","mart"],"meta":{},"group":"products","materialized":"view","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#059669"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","lightdash-explore","mart"],"description":"","columns":{"item_id":{"name":"item_id","description":"Unique identifier for each order item","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"},"dimension":{"type":"string","label":"Item Id"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"type":"number","label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_sku":{"name":"product_sku","description":"Product SKU identifier","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"},"dimension":{"type":"string","label":"Product Sku"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_type":{"name":"product_type","description":"Product type derived from SKU pattern","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"},"dimension":{"type":"string","label":"Product Type"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_items_sold":{"name":"total_items_sold","description":"Total quantity of this product sold","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__products__analytics__product_popularity"},"dimension":{"type":"string","label":"Total Items Sold","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_orders":{"name":"total_orders","description":"Number of unique orders containing this product","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__products__analytics__product_popularity"},"dimension":{"type":"string","label":"Total Orders","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"products","docs":{"show":true,"node_color":"#059669"},"patch_path":"jaffle_shop://models/marts/products/reporting/mart__products__reporting__menu_analytics.yml","build_path":null,"unrendered_config":{"materialized":"view","group":"products","tags":["json","lightdash-explore","mart"],"docs":{"node_color":"#059669","show":true},"contract":{"enforced":false}},"created_at":1793083935.562264,"relation_name":"development.jaffle_shop_dev.mart__products__reporting__menu_analytics","raw_code":"{{\n config(\n materialized=\"view\"\n )\n}}\n\nWITH\n\tmart__products__reporting__menu_analytics AS (\n\t\tSELECT\n\t\t\titem_id,\n\t\t\tportal_source_count,\n\t\t\tproduct_sku,\n\t\t\tproduct_type,\n\t\t\ttotal_items_sold,\n\t\t\ttotal_orders\n\t\tFROM\n\t\t\t{{ ref('int__products__analytics__product_popularity') }}\n\t)\nSELECT\n\t*\nFROM\n\tmart__products__reporting__menu_analytics","doc_blocks":[],"language":"sql","refs":[{"name":"int__products__analytics__product_popularity","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.int__products__analytics__product_popularity"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.mart__sales__reporting__revenue":{"database":"development","schema":"jaffle_shop_dev","name":"mart__sales__reporting__revenue","resource_type":"model","package_name":"jaffle_shop","path":"marts/sales/reporting/mart__sales__reporting__revenue.sql","original_file_path":"models/marts/sales/reporting/mart__sales__reporting__revenue.sql","unique_id":"model.jaffle_shop.mart__sales__reporting__revenue","fqn":["jaffle_shop","marts","sales","reporting","mart__sales__reporting__revenue"],"alias":"mart__sales__reporting__revenue","checksum":{"name":"sha256","checksum":"2fa5464f5bd9ef184f95318398e17707428679d440b4e8b1e972c680a8dde658"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["json","lightdash-explore","mart"],"meta":{"required_filters":[{"datetime":"inThePast 14 days"}]},"group":"sales","materialized":"view","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#059669"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","lightdash-explore","mart"],"description":"","columns":{"customer_id":{"name":"customer_id","description":"Foreign key to customer","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"},"dimension":{"type":"string","label":"Customer ID","group_label":"Customer Fields"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_name":{"name":"customer_name","description":"Customer full name, trimmed of whitespace","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"},"dimension":{"type":"string","label":"Customer Name"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"datetime":{"name":"datetime","description":"Event Datetime Column","meta":{"type":"dim","dimension":{"type":"timestamp","label":"Datetime","sql":"portal_partition_hourly"}},"data_type":"timestamp(6)","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"is_weekend_order":{"name":"is_weekend_order","description":"Boolean flag for weekend orders","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Is Weekend Order"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_date":{"name":"order_date","description":"Date when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"},"dimension":{"type":"date","label":"Order Date","group_label":"Order Fields"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_id":{"name":"order_id","description":"Unique identifier for each order","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"},"dimension":{"type":"string","label":"Order ID","group_label":"Order Fields"},"metrics":{"metric_order_count":{"ai_hint":"Use this to count total orders or analyze order volume trends over time","type":"count_distinct","label":"Number of Orders","group_label":"Order Metrics"}}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_month":{"name":"order_month","description":"Order month","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Order Month"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_quarter":{"name":"order_quarter","description":"Order quarter","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Order Quarter"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_year":{"name":"order_year","description":"Order year","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Order Year"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"type":"number","label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"revenue_tier":{"name":"revenue_tier","description":"Revenue tier classification","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Revenue Tier"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"Foreign key to store","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"},"dimension":{"type":"string","label":"Store ID","group_label":"Store Fields"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_name":{"name":"store_name","description":"Store location name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"},"dimension":{"type":"string","label":"Store Name"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"subtotal_dollars":{"name":"subtotal_dollars","description":"Order subtotal in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Subtotal Dollars","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"tax_dollars":{"name":"tax_dollars","description":"Tax amount in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Tax Dollars","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_dollars":{"name":"total_dollars","description":"Total order amount in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__revenue"},"dimension":{"type":"string","label":"Total Dollars","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_partition_monthly":{"name":"portal_partition_monthly","description":"Monthly Partition Column","meta":{"type":"dim","dimension":{"type":"date","label":"Portal Partition Monthly","hidden":true}},"data_type":"date","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_partition_daily":{"name":"portal_partition_daily","description":"Daily Partition Column","meta":{"type":"dim","dimension":{"type":"date","label":"Portal Partition Daily","hidden":true}},"data_type":"date","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_partition_hourly":{"name":"portal_partition_hourly","description":"Hourly Partition Column","meta":{"type":"dim","dimension":{"type":"timestamp","label":"Portal Partition Hourly","hidden":true}},"data_type":"timestamp(6)","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{"required_filters":[{"datetime":"inThePast 14 days"}]},"group":"sales","docs":{"show":true,"node_color":"#059669"},"patch_path":"jaffle_shop://models/marts/sales/reporting/mart__sales__reporting__revenue.yml","build_path":null,"unrendered_config":{"materialized":"view","group":"sales","tags":["json","lightdash-explore","mart"],"meta":{"required_filters":[{"datetime":"inThePast 14 days"}]},"docs":{"node_color":"#059669","show":true},"contract":{"enforced":false}},"created_at":1793083935.568948,"relation_name":"development.jaffle_shop_dev.mart__sales__reporting__revenue","raw_code":"{{\n config(\n materialized=\"view\"\n )\n}}\n\nWITH\n\tmart__sales__reporting__revenue AS (\n\t\tSELECT\n\t\t\tcustomer_id,\n\t\t\tcustomer_name,\n\t\t\tdatetime,\n\t\t\tday_of_week(order_date) IN (6, 7) AS is_weekend_order,\n\t\t\torder_date,\n\t\t\torder_id,\n\t\t\tEXTRACT(\n\t\t\t\tMONTH\n\t\t\t\tFROM\n\t\t\t\t\torder_date\n\t\t\t) AS order_month,\n\t\t\tEXTRACT(\n\t\t\t\tQUARTER\n\t\t\t\tFROM\n\t\t\t\t\torder_date\n\t\t\t) AS order_quarter,\n\t\t\tEXTRACT(\n\t\t\t\tYEAR\n\t\t\t\tFROM\n\t\t\t\t\torder_date\n\t\t\t) AS order_year,\n\t\t\tportal_source_count,\n\t\t\tCASE\n\t\t\t\tWHEN order_total_dollars >= 15.00 THEN 'High'\n\t\t\t\tWHEN order_total_dollars >= 8.00 THEN 'Medium'\n\t\t\t\tELSE 'Low'\n\t\t\tEND AS revenue_tier,\n\t\t\tstore_id,\n\t\t\tstore_name,\n\t\t\tCAST(subtotal_cents AS DECIMAL(10, 2)) / 100.0 AS subtotal_dollars,\n\t\t\tCAST(tax_paid_cents AS DECIMAL(10, 2)) / 100.0 AS tax_dollars,\n\t\t\torder_total_dollars AS total_dollars,\n\t\t\t-- partition columns\n\t\t\tportal_partition_monthly,\n\t\t\tportal_partition_daily,\n\t\t\tportal_partition_hourly\n\t\tFROM\n\t\t\t{{ ref('int__sales__orders__enriched') }}\n\t)\nSELECT\n\t*\nFROM\n\tmart__sales__reporting__revenue","doc_blocks":[],"language":"sql","refs":[{"name":"int__sales__orders__enriched","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.int__sales__orders__enriched"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.mart__sales__reporting__profitability":{"database":"development","schema":"jaffle_shop_dev","name":"mart__sales__reporting__profitability","resource_type":"model","package_name":"jaffle_shop","path":"marts/sales/reporting/mart__sales__reporting__profitability.sql","original_file_path":"models/marts/sales/reporting/mart__sales__reporting__profitability.sql","unique_id":"model.jaffle_shop.mart__sales__reporting__profitability","fqn":["jaffle_shop","marts","sales","reporting","mart__sales__reporting__profitability"],"alias":"mart__sales__reporting__profitability","checksum":{"name":"sha256","checksum":"92046229af0f08171a3cfb1b058d3f0d6e7dbfac0d1006ef1da95fa3ce477d45"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["json","lightdash-explore","mart"],"meta":{"required_filters":[{"datetime":"inThePast 14 days"}]},"group":"sales","materialized":"view","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#059669"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","lightdash-explore","mart"],"description":"","columns":{"avg_order_value_dollars":{"name":"avg_order_value_dollars","description":"Average order value in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__profitability"},"dimension":{"type":"string","label":"Avg Order Value Dollars","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"datetime":{"name":"datetime","description":"Event Datetime Column","meta":{"type":"dim","dimension":{"type":"timestamp","label":"Datetime","sql":"portal_partition_hourly"}},"data_type":"timestamp(6)","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_count":{"name":"order_count","description":"Number of orders","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__profitability"},"dimension":{"type":"string","label":"Order Count","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_date":{"name":"order_date","description":"Date when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"},"dimension":{"type":"date","label":"Order Date","group_label":"Order Fields"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_year_month":{"name":"order_year_month","description":"Order year-month","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__sales__reporting__profitability"},"dimension":{"type":"string","label":"Order Year Month"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"type":"number","label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"revenue_per_day":{"name":"revenue_per_day","description":"Daily revenue per store","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__profitability"},"dimension":{"type":"string","label":"Revenue Per Day","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"Foreign key to store","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"},"dimension":{"type":"string","label":"Store ID","group_label":"Store Fields"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_name":{"name":"store_name","description":"Store location name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"},"dimension":{"type":"string","label":"Store Name"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_revenue_dollars":{"name":"total_revenue_dollars","description":"Total revenue in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__profitability"},"dimension":{"type":"string","label":"Total Revenue Dollars","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_tax_collected_dollars":{"name":"total_tax_collected_dollars","description":"Total tax collected in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__sales__reporting__profitability"},"dimension":{"type":"string","label":"Total Tax Collected Dollars","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_partition_monthly":{"name":"portal_partition_monthly","description":"Monthly Partition Column","meta":{"type":"dim","dimension":{"type":"date","label":"Portal Partition Monthly","hidden":true}},"data_type":"date","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_partition_daily":{"name":"portal_partition_daily","description":"Daily Partition Column","meta":{"type":"dim","dimension":{"type":"date","label":"Portal Partition Daily","hidden":true}},"data_type":"date","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_partition_hourly":{"name":"portal_partition_hourly","description":"Hourly Partition Column","meta":{"type":"dim","dimension":{"type":"timestamp","label":"Portal Partition Hourly","hidden":true}},"data_type":"timestamp(6)","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{"required_filters":[{"datetime":"inThePast 14 days"}]},"group":"sales","docs":{"show":true,"node_color":"#059669"},"patch_path":"jaffle_shop://models/marts/sales/reporting/mart__sales__reporting__profitability.yml","build_path":null,"unrendered_config":{"materialized":"view","group":"sales","tags":["json","lightdash-explore","mart"],"meta":{"required_filters":[{"datetime":"inThePast 14 days"}]},"docs":{"node_color":"#059669","show":true},"contract":{"enforced":false}},"created_at":1793083935.572033,"relation_name":"development.jaffle_shop_dev.mart__sales__reporting__profitability","raw_code":"{{\n config(\n materialized=\"view\"\n )\n}}\n\nWITH\n\tmart__sales__reporting__profitability AS (\n\t\tSELECT\n\t\t\tAVG(order_total_dollars) AS avg_order_value_dollars,\n\t\t\tdatetime,\n\t\t\tCOUNT(*) AS order_count,\n\t\t\torder_date,\n\t\t\tDATE_TRUNC('month', order_date) AS order_year_month,\n\t\t\tsum(portal_source_count) AS portal_source_count,\n\t\t\tSUM(order_total_dollars) AS revenue_per_day,\n\t\t\tstore_id,\n\t\t\tstore_name,\n\t\t\tSUM(order_total_dollars) AS total_revenue_dollars,\n\t\t\tSUM(CAST(tax_paid_cents AS DECIMAL(10, 2)) / 100.0) AS total_tax_collected_dollars,\n\t\t\t-- partition columns\n\t\t\tportal_partition_monthly,\n\t\t\tportal_partition_daily,\n\t\t\tportal_partition_hourly\n\t\tFROM\n\t\t\t{{ ref('int__sales__orders__enriched') }}\n\t\tGROUP BY\n\t\t\tdatetime,\n\t\t\torder_date,\n\t\t\tDATE_TRUNC('month', order_date),\n\t\t\tstore_id,\n\t\t\tstore_name,\n\t\t\tportal_partition_monthly,\n\t\t\tportal_partition_daily,\n\t\t\tportal_partition_hourly\n\t)\nSELECT\n\t*\nFROM\n\tmart__sales__reporting__profitability","doc_blocks":[],"language":"sql","refs":[{"name":"int__sales__orders__enriched","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.int__sales__orders__enriched"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics":{"database":"development","schema":"jaffle_shop_dev","name":"mart__analytics__dashboard__comprehensive_analytics","resource_type":"model","package_name":"jaffle_shop","path":"marts/analytics/dashboard/mart__analytics__dashboard__comprehensive_analytics.sql","original_file_path":"models/marts/analytics/dashboard/mart__analytics__dashboard__comprehensive_analytics.sql","unique_id":"model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics","fqn":["jaffle_shop","marts","analytics","dashboard","mart__analytics__dashboard__comprehensive_analytics"],"alias":"mart__analytics__dashboard__comprehensive_analytics","checksum":{"name":"sha256","checksum":"f632e9b79f77dd90892f2e965d5670ebb1d2c56d54de6185c71b086cc4673837"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["json","lightdash-explore","mart"],"meta":{},"group":"analytics","materialized":"view","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#059669"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["json","lightdash-explore","mart"],"description":"","columns":{"business_impact_score":{"name":"business_impact_score","description":"Business impact score based on cost efficiency (0-100)","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics"},"dimension":{"type":"string","label":"Business Impact Score","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"cost_to_price_ratio":{"name":"cost_to_price_ratio","description":"Individual supply cost as ratio of selling price","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Cost To Price Ratio","hidden":true}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"is_perishable_supply":{"name":"is_perishable_supply","description":"Whether this supply is perishable","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__products__reporting__cost_efficiency"},"dimension":{"type":"string","label":"Is Perishable Supply"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"type":"number","label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_name":{"name":"product_name","description":"Product name, trimmed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"},"dimension":{"type":"string","label":"Product Name","group_label":"Product Fields"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_price_dollars":{"name":"product_price_dollars","description":"Product price in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"},"dimension":{"type":"string","label":"Product Price Dollars","hidden":true},"metrics":{"metric_product_price_dollars_sum":{"ai_hint":"Use this metric to calculate total product catalog value or analyze average product pricing","type":"sum","label":"Total Product Value","group_label":"Product Metrics"}}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_sku":{"name":"product_sku","description":"Product SKU identifier","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"},"dimension":{"type":"string","label":"Product SKU","group_label":"Product Fields"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_type":{"name":"product_type","description":"Product type derived from SKU pattern","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"},"dimension":{"type":"string","label":"Product Type","group_label":"Product Fields"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"strategic_recommendation":{"name":"strategic_recommendation","description":"Strategic business recommendation","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics"},"dimension":{"type":"string","label":"Strategic Recommendation"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_items_sold":{"name":"total_items_sold","description":"Total quantity of this product sold","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__products__analytics__product_popularity"},"dimension":{"type":"string","label":"Total Items Sold","hidden":true},"metrics":{"metric_total_items_sold":{"ai_hint":"Use this to analyze product sales volume and inventory demand for best-selling items","type":"sum","label":"Total Items Sold","group_label":"Product Popularity"},"metric_avg_items_per_order":{"ai_hint":"Use this to understand typical order quantities for inventory and fulfillment planning","type":"average","label":"Average Items Per Order","group_label":"Product Popularity"}}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_orders":{"name":"total_orders","description":"Number of unique orders containing this product","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__products__analytics__product_popularity"},"dimension":{"type":"string","label":"Total Orders","hidden":true},"metrics":{"metric_product_order_count":{"ai_hint":"Use this to understand product popularity and which items are frequently purchased together","type":"sum","label":"Orders Containing Product","group_label":"Product Popularity"}}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"analytics","docs":{"show":true,"node_color":"#059669"},"patch_path":"jaffle_shop://models/marts/analytics/dashboard/mart__analytics__dashboard__comprehensive_analytics.yml","build_path":null,"unrendered_config":{"materialized":"view","group":"analytics","tags":["json","lightdash-explore","mart"],"docs":{"node_color":"#059669","show":true},"contract":{"enforced":false}},"created_at":1793083935.5758169,"relation_name":"development.jaffle_shop_dev.mart__analytics__dashboard__comprehensive_analytics","raw_code":"{{\n config(\n materialized=\"view\"\n )\n}}\n\nWITH\n\tmart__analytics__dashboard__comprehensive_analytics AS (\n\t\tSELECT\n\t\t\tCASE\n\t\t\t\tWHEN mart__products__reporting__cost_efficiency.cost_efficiency_category = 'Highly Efficient' THEN 100\n\t\t\t\tWHEN mart__products__reporting__cost_efficiency.cost_efficiency_category = 'Efficient' THEN 85\n\t\t\t\tWHEN mart__products__reporting__cost_efficiency.cost_efficiency_category = 'Moderate' THEN 70\n\t\t\t\tELSE 50\n\t\t\tEND AS business_impact_score,\n\t\t\tmart__products__reporting__cost_efficiency.cost_to_price_ratio,\n\t\t\tmart__products__reporting__cost_efficiency.is_perishable_supply,\n\t\t\tmart__products__reporting__cost_efficiency.portal_source_count,\n\t\t\tmart__products__reporting__cost_efficiency.product_name,\n\t\t\tmart__products__reporting__cost_efficiency.product_price_dollars,\n\t\t\tmart__products__reporting__menu_analytics.product_sku,\n\t\t\tmart__products__reporting__menu_analytics.product_type,\n\t\t\tCASE\n\t\t\t\tWHEN mart__products__reporting__cost_efficiency.cost_efficiency_category = 'Highly Efficient' THEN 'Promote & Expand'\n\t\t\t\tWHEN mart__products__reporting__cost_efficiency.cost_efficiency_category = 'Efficient' THEN 'Monitor Performance'\n\t\t\t\tWHEN mart__products__reporting__cost_efficiency.cost_efficiency_category = 'Moderate' THEN 'Optimize Costs'\n\t\t\t\tELSE 'Review Strategy'\n\t\t\tEND AS strategic_recommendation,\n\t\t\tmart__products__reporting__menu_analytics.total_items_sold,\n\t\t\tmart__products__reporting__menu_analytics.total_orders\n\t\tFROM\n\t\t\t{{ ref('mart__products__reporting__menu_analytics') }} mart__products__reporting__menu_analytics\n\t\t\tLEFT JOIN {{ ref('mart__products__reporting__cost_efficiency') }} mart__products__reporting__cost_efficiency ON mart__products__reporting__menu_analytics.product_sku = mart__products__reporting__cost_efficiency.product_sku\n\t)\nSELECT\n\t*\nFROM\n\tmart__analytics__dashboard__comprehensive_analytics","doc_blocks":[],"language":"sql","refs":[{"name":"mart__products__reporting__menu_analytics","package":null,"version":null},{"name":"mart__products__reporting__cost_efficiency","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.mart__products__reporting__menu_analytics","model.jaffle_shop.mart__products__reporting__cost_efficiency"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.int__customers__profiles__summary":{"database":"development","schema":"jaffle_shop_dev","name":"int__customers__profiles__summary","resource_type":"model","package_name":"jaffle_shop","path":"intermediate/customers/profiles/int__customers__profiles__summary.sql","original_file_path":"models/intermediate/customers/profiles/int__customers__profiles__summary.sql","unique_id":"model.jaffle_shop.int__customers__profiles__summary","fqn":["jaffle_shop","intermediate","customers","profiles","int__customers__profiles__summary"],"alias":"int__customers__profiles__summary","checksum":{"name":"sha256","checksum":"41250064d49f00fabea3a0c5ec7b604be27f73251cb9ef0a86f9950979f380a5"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["intermediate","json"],"meta":{},"group":"customers","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#DAA520"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["intermediate","json"],"description":"","columns":{"customer_first_name":{"name":"customer_first_name","description":"Customer first name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_id":{"name":"customer_id","description":"Unique identifier for each customer","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_last_name":{"name":"customer_last_name","description":"Customer last name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_name":{"name":"customer_name","description":"Customer full name, trimmed of whitespace","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_segment":{"name":"customer_segment","description":"Customer segment classification based on order count","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.int__customers__profiles__summary"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"has_last_name":{"name":"has_last_name","description":"Whether customer provided a last name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.int__customers__profiles__summary"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_orders":{"name":"total_orders","description":"Total number of orders placed by customer","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__customers__profiles__summary"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"customers","docs":{"show":true,"node_color":"#DAA520"},"patch_path":"jaffle_shop://models/intermediate/customers/profiles/int__customers__profiles__summary.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","group":"customers","tags":["intermediate","json"],"docs":{"node_color":"#DAA520","show":true},"contract":{"enforced":false}},"created_at":1793083935.628439,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tint__customers__profiles__summary AS (\n\t\tSELECT\n\t\t\tstg__customers__profiles__clean.customer_first_name,\n\t\t\tstg__customers__profiles__clean.customer_id,\n\t\t\tstg__customers__profiles__clean.customer_last_name,\n\t\t\tstg__customers__profiles__clean.customer_name,\n\t\t\t{{ customer_segment() }} AS customer_segment,\n\t\t\tstg__customers__profiles__clean.customer_last_name IS NOT NULL AS has_last_name,\n\t\t\tsum(\n\t\t\t\tstg__customers__profiles__clean.portal_source_count\n\t\t\t) AS portal_source_count,\n\t\t\tCOUNT(stg__sales__orders__standardized.order_id) AS total_orders\n\t\tFROM\n\t\t\t{{ ref('stg__customers__profiles__clean') }} stg__customers__profiles__clean\n\t\t\tLEFT JOIN {{ ref('stg__sales__orders__standardized') }} stg__sales__orders__standardized ON stg__customers__profiles__clean.customer_id = stg__sales__orders__standardized.customer_id\n\t\tGROUP BY\n\t\t\tstg__customers__profiles__clean.customer_first_name,\n\t\t\tstg__customers__profiles__clean.customer_id,\n\t\t\tstg__customers__profiles__clean.customer_last_name,\n\t\t\tstg__customers__profiles__clean.customer_name\n\t)\nSELECT\n\t*\nFROM\n\tint__customers__profiles__summary","doc_blocks":[],"language":"sql","refs":[{"name":"stg__customers__profiles__clean","package":null,"version":null},{"name":"stg__sales__orders__standardized","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":["macro.jaffle_shop.customer_segment"],"nodes":["model.jaffle_shop.stg__customers__profiles__clean","model.jaffle_shop.stg__sales__orders__standardized"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.int__products__analytics__product_popularity":{"database":"development","schema":"jaffle_shop_dev","name":"int__products__analytics__product_popularity","resource_type":"model","package_name":"jaffle_shop","path":"intermediate/products/analytics/int__products__analytics__product_popularity.sql","original_file_path":"models/intermediate/products/analytics/int__products__analytics__product_popularity.sql","unique_id":"model.jaffle_shop.int__products__analytics__product_popularity","fqn":["jaffle_shop","intermediate","products","analytics","int__products__analytics__product_popularity"],"alias":"int__products__analytics__product_popularity","checksum":{"name":"sha256","checksum":"49fea0d39aaeabc54f366cd5764defac0160afc7e2574c87afef171435a4903f"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["intermediate","json"],"meta":{},"group":"products","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#DAA520"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["intermediate","json"],"description":"","columns":{"item_id":{"name":"item_id","description":"Unique identifier for each order item","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_sku":{"name":"product_sku","description":"Product SKU identifier","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_type":{"name":"product_type","description":"Product type derived from SKU pattern","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__items__order_details"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_items_sold":{"name":"total_items_sold","description":"Total quantity of this product sold","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__products__analytics__product_popularity"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"total_orders":{"name":"total_orders","description":"Number of unique orders containing this product","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__products__analytics__product_popularity"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"products","docs":{"show":true,"node_color":"#DAA520"},"patch_path":"jaffle_shop://models/intermediate/products/analytics/int__products__analytics__product_popularity.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","group":"products","tags":["intermediate","json"],"docs":{"node_color":"#DAA520","show":true},"contract":{"enforced":false}},"created_at":1793083935.62955,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tint__products__analytics__product_popularity AS (\n\t\tSELECT\n\t\t\titem_id,\n\t\t\tsum(portal_source_count) AS portal_source_count,\n\t\t\tproduct_sku,\n\t\t\tproduct_type,\n\t\t\tCOUNT(*) AS total_items_sold,\n\t\t\tCOUNT(DISTINCT order_id) AS total_orders\n\t\tFROM\n\t\t\t{{ ref('stg__sales__items__order_details') }}\n\t\tGROUP BY\n\t\t\titem_id,\n\t\t\tproduct_sku,\n\t\t\tproduct_type\n\t)\nSELECT\n\t*\nFROM\n\tint__products__analytics__product_popularity","doc_blocks":[],"language":"sql","refs":[{"name":"stg__sales__items__order_details","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.stg__sales__items__order_details"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.int__sales__orders__enriched":{"database":"development","schema":"jaffle_shop_dev","name":"int__sales__orders__enriched","resource_type":"model","package_name":"jaffle_shop","path":"intermediate/sales/orders/int__sales__orders__enriched.sql","original_file_path":"models/intermediate/sales/orders/int__sales__orders__enriched.sql","unique_id":"model.jaffle_shop.int__sales__orders__enriched","fqn":["jaffle_shop","intermediate","sales","orders","int__sales__orders__enriched"],"alias":"int__sales__orders__enriched","checksum":{"name":"sha256","checksum":"8caf6828d75ffc47b0d22853b7c3ba56d8b52bc3143ca54ca12bc249c6d068eb"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["intermediate","json"],"meta":{},"group":"sales","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#DAA520"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["intermediate","json"],"description":"","columns":{"customer_first_name":{"name":"customer_first_name","description":"Customer first name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_id":{"name":"customer_id","description":"Foreign key to customer","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_name":{"name":"customer_name","description":"Customer full name, trimmed of whitespace","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_date":{"name":"order_date","description":"Date when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_id":{"name":"order_id","description":"Unique identifier for each order","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total_cents":{"name":"order_total_cents","description":"Total order amount in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total_dollars":{"name":"order_total_dollars","description":"Order total in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__sales__orders__enriched"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"ordered_at":{"name":"ordered_at","description":"Timestamp when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"Foreign key to store","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_name":{"name":"store_name","description":"Store location name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_tax_rate":{"name":"store_tax_rate","description":"Local tax rate for the store","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"subtotal_cents":{"name":"subtotal_cents","description":"Order subtotal in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"tax_paid_cents":{"name":"tax_paid_cents","description":"Tax amount paid in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"sales","docs":{"show":true,"node_color":"#DAA520"},"patch_path":"jaffle_shop://models/intermediate/sales/orders/int__sales__orders__enriched.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","group":"sales","tags":["intermediate","json"],"docs":{"node_color":"#DAA520","show":true},"contract":{"enforced":false}},"created_at":1793083935.631244,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tint__sales__orders__enriched AS (\n\t\tSELECT\n\t\t\tstg__customers__profiles__clean.customer_first_name,\n\t\t\tstg__sales__orders__standardized.customer_id,\n\t\t\tstg__customers__profiles__clean.customer_name,\n\t\t\tstg__sales__orders__standardized.order_date,\n\t\t\tstg__sales__orders__standardized.order_id,\n\t\t\tstg__sales__orders__standardized.order_total_cents,\n\t\t\tCAST(\n\t\t\t\tstg__sales__orders__standardized.order_total_cents AS DECIMAL(10, 2)\n\t\t\t) / 100.0 AS order_total_dollars,\n\t\t\tstg__sales__orders__standardized.ordered_at,\n\t\t\tstg__sales__orders__standardized.portal_source_count,\n\t\t\tstg__sales__orders__standardized.store_id,\n\t\t\tstg__sales__stores__locations.store_name,\n\t\t\tstg__sales__stores__locations.store_tax_rate,\n\t\t\tstg__sales__orders__standardized.subtotal_cents,\n\t\t\tstg__sales__orders__standardized.tax_paid_cents\n\t\tFROM\n\t\t\t{{ ref('stg__sales__orders__standardized') }} stg__sales__orders__standardized\n\t\t\tLEFT JOIN {{ ref('stg__customers__profiles__clean') }} stg__customers__profiles__clean ON stg__sales__orders__standardized.customer_id = stg__customers__profiles__clean.customer_id\n\t\t\tLEFT JOIN {{ ref('stg__sales__stores__locations') }} stg__sales__stores__locations ON stg__sales__orders__standardized.store_id = stg__sales__stores__locations.store_id\n\t)\nSELECT\n\t*\nFROM\n\tint__sales__orders__enriched","doc_blocks":[],"language":"sql","refs":[{"name":"stg__sales__orders__standardized","package":null,"version":null},{"name":"stg__customers__profiles__clean","package":null,"version":null},{"name":"stg__sales__stores__locations","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.stg__sales__orders__standardized","model.jaffle_shop.stg__customers__profiles__clean","model.jaffle_shop.stg__sales__stores__locations"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.int__sales__orders__regional_combined":{"database":"development","schema":"jaffle_shop_dev","name":"int__sales__orders__regional_combined","resource_type":"model","package_name":"jaffle_shop","path":"intermediate/sales/orders/int__sales__orders__regional_combined.sql","original_file_path":"models/intermediate/sales/orders/int__sales__orders__regional_combined.sql","unique_id":"model.jaffle_shop.int__sales__orders__regional_combined","fqn":["jaffle_shop","intermediate","sales","orders","int__sales__orders__regional_combined"],"alias":"int__sales__orders__regional_combined","checksum":{"name":"sha256","checksum":"b988eded0f7a248aabaa73ad50962b0a8b6db43ea229e52a98e8232c49dfeeb5"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["intermediate","json"],"meta":{},"group":"sales","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["intermediate","json"],"description":"Union of orders with regional classification for consolidated reporting across all stores","columns":{"customer_first_name":{"name":"customer_first_name","description":"Customer first name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_id":{"name":"customer_id","description":"Foreign key to customer","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_name":{"name":"customer_name","description":"Customer full name, trimmed of whitespace","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_date":{"name":"order_date","description":"Date when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_id":{"name":"order_id","description":"Unique identifier for each order","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total_cents":{"name":"order_total_cents","description":"Total order amount in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total_dollars":{"name":"order_total_dollars","description":"Order total in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__sales__orders__enriched"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"ordered_at":{"name":"ordered_at","description":"Timestamp when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"region":{"name":"region","description":"Geographic region classification","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.int__sales__orders__regional_combined"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"Foreign key to store","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_name":{"name":"store_name","description":"Store location name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_tax_rate":{"name":"store_tax_rate","description":"Local tax rate for the store","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"subtotal_cents":{"name":"subtotal_cents","description":"Order subtotal in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"tax_paid_cents":{"name":"tax_paid_cents","description":"Tax amount paid in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"sales","docs":{"show":true,"node_color":null},"patch_path":"jaffle_shop://models/intermediate/sales/orders/int__sales__orders__regional_combined.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","group":"sales","tags":["intermediate","json"],"docs":{"show":true},"contract":{"enforced":false}},"created_at":1793083935.632844,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tint__sales__orders__regional_combined AS (\n\t\tSELECT\n\t\t\tcustomer_first_name,\n\t\t\tcustomer_id,\n\t\t\tcustomer_name,\n\t\t\torder_date,\n\t\t\torder_id,\n\t\t\torder_total_cents,\n\t\t\torder_total_dollars,\n\t\t\tordered_at,\n\t\t\tportal_source_count,\n\t\t\tCASE\n\t\t\t\tWHEN store_name IN ('Philadelphia', 'Brooklyn') THEN 'East Coast'\n\t\t\t\tWHEN store_name IN ('San Francisco', 'Los Angeles') THEN 'West Coast'\n\t\t\t\tELSE 'Other'\n\t\t\tEND AS region,\n\t\t\tstore_id,\n\t\t\tstore_name,\n\t\t\tstore_tax_rate,\n\t\t\tsubtotal_cents,\n\t\t\ttax_paid_cents\n\t\tFROM\n\t\t\t{{ ref('int__sales__orders__enriched') }}\n\t\tUNION ALL\n\t\tSELECT\n\t\t\tcustomer_first_name,\n\t\t\tcustomer_id,\n\t\t\tcustomer_name,\n\t\t\torder_date,\n\t\t\torder_id,\n\t\t\torder_total_cents,\n\t\t\torder_total_dollars,\n\t\t\tordered_at,\n\t\t\tportal_source_count,\n\t\t\tCASE\n\t\t\t\tWHEN store_name IN ('Philadelphia', 'Brooklyn') THEN 'East Coast'\n\t\t\t\tWHEN store_name IN ('San Francisco', 'Los Angeles') THEN 'West Coast'\n\t\t\t\tELSE 'Other'\n\t\t\tEND AS region,\n\t\t\tstore_id,\n\t\t\tstore_name,\n\t\t\tstore_tax_rate,\n\t\t\tsubtotal_cents,\n\t\t\ttax_paid_cents\n\t\tFROM\n\t\t\t{{ ref('int__sales__orders__enriched') }}\n\t)\nSELECT\n\t*\nFROM\n\tint__sales__orders__regional_combined","doc_blocks":[],"language":"sql","refs":[{"name":"int__sales__orders__enriched","package":null,"version":null},{"name":"int__sales__orders__enriched","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.int__sales__orders__enriched"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.int__sales__analytics__rolling_30day":{"database":"development","schema":"jaffle_shop_dev","name":"int__sales__analytics__rolling_30day","resource_type":"model","package_name":"jaffle_shop","path":"intermediate/sales/analytics/int__sales__analytics__rolling_30day.sql","original_file_path":"models/intermediate/sales/analytics/int__sales__analytics__rolling_30day.sql","unique_id":"model.jaffle_shop.int__sales__analytics__rolling_30day","fqn":["jaffle_shop","intermediate","sales","analytics","int__sales__analytics__rolling_30day"],"alias":"int__sales__analytics__rolling_30day","checksum":{"name":"sha256","checksum":"78f7c85c824c65a077a0a270549607daa259992d89dbaf3c9845a746d4b4f806"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["intermediate","json"],"meta":{},"group":"sales","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["intermediate","json"],"description":"30-day rolling window analysis of sales metrics partitioned by store for trend analysis","columns":{"order_date":{"name":"order_date","description":"Date when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_id_count":{"name":"order_id_count","description":"Number of orders in the last 30 days","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"number","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total_dollars_sum":{"name":"order_total_dollars_sum","description":"Revenue metrics for the last 30 days (sum, min, max)","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__sales__orders__enriched"}},"data_type":"number","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total_dollars_min":{"name":"order_total_dollars_min","description":"Revenue metrics for the last 30 days (sum, min, max)","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__sales__orders__enriched"}},"data_type":"number","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total_dollars_max":{"name":"order_total_dollars_max","description":"Revenue metrics for the last 30 days (sum, min, max)","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__sales__orders__enriched"}},"data_type":"number","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"Foreign key to store","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_name":{"name":"store_name","description":"Store location name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_partition_daily":{"name":"portal_partition_daily","description":"Portal Partition Daily","meta":{"type":"dim"},"data_type":"date","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"sales","docs":{"show":true,"node_color":null},"patch_path":"jaffle_shop://models/intermediate/sales/analytics/int__sales__analytics__rolling_30day.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","group":"sales","tags":["intermediate","json"],"docs":{"show":true},"contract":{"enforced":false}},"created_at":1793083935.63458,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tint__sales__analytics__rolling_30day AS (\n\t\tSELECT\n\t\t\torder_date,\n\t\t\tcount(order_id) AS order_id_count,\n\t\t\tsum(order_total_dollars) AS order_total_dollars_sum,\n\t\t\tmin(order_total_dollars) AS order_total_dollars_min,\n\t\t\tmax(order_total_dollars) AS order_total_dollars_max,\n\t\t\tstore_id,\n\t\t\tstore_name,\n\t\t\t-- partition columns\n\t\t\t_ext_event_date AS portal_partition_daily\n\t\tFROM\n\t\t\t{{ _ext_event_dates_table() }}\n\t\t\tINNER JOIN {{ ref('int__sales__orders__enriched') }} ON portal_partition_daily <= _ext_event_date\n\t\t\tAND portal_partition_daily >= date_add('day', -30, _ext_event_date)\n\t\tGROUP BY\n\t\t\torder_date,\n\t\t\tstore_id,\n\t\t\tstore_name,\n\t\t\t_ext_event_date\n\t)\nSELECT\n\t*\nFROM\n\tint__sales__analytics__rolling_30day","doc_blocks":[],"language":"sql","refs":[{"name":"int__sales__orders__enriched","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":["macro.jaffle_shop._ext_event_dates_table"],"nodes":["model.jaffle_shop.int__sales__orders__enriched"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.int__sales__analytics__monthly_revenue":{"database":"development","schema":"jaffle_shop_dev","name":"int__sales__analytics__monthly_revenue","resource_type":"model","package_name":"jaffle_shop","path":"intermediate/sales/analytics/int__sales__analytics__monthly_revenue.sql","original_file_path":"models/intermediate/sales/analytics/int__sales__analytics__monthly_revenue.sql","unique_id":"model.jaffle_shop.int__sales__analytics__monthly_revenue","fqn":["jaffle_shop","intermediate","sales","analytics","int__sales__analytics__monthly_revenue"],"alias":"int__sales__analytics__monthly_revenue","checksum":{"name":"sha256","checksum":"cdf26dc4ad7142b7e0725fe845726a2bf53624200f27215c1ca466116e3d137c"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["intermediate","json"],"meta":{},"group":"sales","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["intermediate","json"],"description":"Monthly rollup of sales data aggregating revenue, orders, and customer metrics by store","columns":{"customer_first_name":{"name":"customer_first_name","description":"Customer first name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_id":{"name":"customer_id","description":"Foreign key to customer","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer_name":{"name":"customer_name","description":"Customer full name, trimmed of whitespace","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__customers__profiles__clean"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"datetime":{"name":"datetime","description":"Datetime","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.int__sales__analytics__monthly_revenue"},"dimension":{"label":"Datetime","time_intervals":["MONTH","YEAR"]}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_date":{"name":"order_date","description":"Date when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_id":{"name":"order_id","description":"Unique identifier for each order","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"ordered_at":{"name":"ordered_at","description":"Timestamp when order was placed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"Foreign key to store","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__orders__standardized"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_name":{"name":"store_name","description":"Store location name","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__sales__stores__locations"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"sales","docs":{"show":true,"node_color":null},"patch_path":"jaffle_shop://models/intermediate/sales/analytics/int__sales__analytics__monthly_revenue.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","group":"sales","tags":["intermediate","json"],"docs":{"show":true},"contract":{"enforced":false}},"created_at":1793083935.636155,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tint__sales__analytics__monthly_revenue AS (\n\t\tSELECT\n\t\t\tcustomer_first_name,\n\t\t\tcustomer_id,\n\t\t\tcustomer_name,\n\t\t\tdate_trunc('month', datetime) AS datetime,\n\t\t\torder_date,\n\t\t\torder_id,\n\t\t\tordered_at,\n\t\t\tsum(portal_source_count) AS portal_source_count,\n\t\t\tstore_id,\n\t\t\tstore_name\n\t\tFROM\n\t\t\t{{ ref('int__sales__orders__enriched') }}\n\t\tGROUP BY\n\t\t\tcustomer_first_name,\n\t\t\tcustomer_id,\n\t\t\tcustomer_name,\n\t\t\tdate_trunc('month', datetime),\n\t\t\torder_date,\n\t\t\torder_id,\n\t\t\tordered_at,\n\t\t\tstore_id,\n\t\t\tstore_name\n\t)\nSELECT\n\t*\nFROM\n\tint__sales__analytics__monthly_revenue","doc_blocks":[],"language":"sql","refs":[{"name":"int__sales__orders__enriched","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":["model.jaffle_shop.int__sales__orders__enriched"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"model.jaffle_shop.int__supply_chain__supplies__cost_analysis":{"database":"development","schema":"jaffle_shop_dev","name":"int__supply_chain__supplies__cost_analysis","resource_type":"model","package_name":"jaffle_shop","path":"intermediate/supply_chain/supplies/int__supply_chain__supplies__cost_analysis.sql","original_file_path":"models/intermediate/supply_chain/supplies/int__supply_chain__supplies__cost_analysis.sql","unique_id":"model.jaffle_shop.int__supply_chain__supplies__cost_analysis","fqn":["jaffle_shop","intermediate","supply_chain","supplies","int__supply_chain__supplies__cost_analysis"],"alias":"int__supply_chain__supplies__cost_analysis","checksum":{"name":"sha256","checksum":"c569a2c4c33d074e0dcf3e5c65df4e583b8730580d837f2f8ccb474b59bedfca"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":["intermediate","json"],"meta":{},"group":"supply_chain","materialized":"ephemeral","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":"#DAA520"},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"access":"protected","freshness":null},"tags":["intermediate","json"],"description":"","columns":{"cost_cents":{"name":"cost_cents","description":"Supply cost in cents","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"cost_dollars":{"name":"cost_dollars","description":"Supply cost in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"cost_tier":{"name":"cost_tier","description":"Supply cost tier classification","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.int__supply_chain__supplies__cost_analysis"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"is_perishable":{"name":"is_perishable","description":"Boolean flag for perishable supplies","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"portal_source_count":{"name":"portal_source_count","description":"Portal Source Count","meta":{"type":"fct","dimension":{"label":"Portal Source Count","hidden":true},"metrics":{"metric_portal_source_count":{"type":"sum","label":"Portal Source Count"}}},"data_type":"bigint","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_name":{"name":"product_name","description":"Product name, trimmed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_price_dollars":{"name":"product_price_dollars","description":"Product price in dollars","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_sku":{"name":"product_sku","description":"Associated product SKU","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"product_type":{"name":"product_type","description":"Product category (jaffle, beverage)","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__products__catalog__catalog"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"supply_category":{"name":"supply_category","description":"Supply category classification","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"supply_id":{"name":"supply_id","description":"Unique identifier for each supply item","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"supply_name":{"name":"supply_name","description":"Supply item name, trimmed","meta":{"type":"dim","origin":{"id":"model.jaffle_shop.stg__supply_chain__supplies__inventory"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"supply_to_price_ratio":{"name":"supply_to_price_ratio","description":"Supply cost as percentage of product price","meta":{"type":"fct","origin":{"id":"model.jaffle_shop.int__supply_chain__supplies__cost_analysis"}},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"group":"supply_chain","docs":{"show":true,"node_color":"#DAA520"},"patch_path":"jaffle_shop://models/intermediate/supply_chain/supplies/int__supply_chain__supplies__cost_analysis.yml","build_path":null,"unrendered_config":{"materialized":"ephemeral","group":"supply_chain","tags":["intermediate","json"],"docs":{"node_color":"#DAA520","show":true},"contract":{"enforced":false}},"created_at":1793083935.638477,"relation_name":null,"raw_code":"{{\n config(\n materialized=\"ephemeral\"\n )\n}}\n\nWITH\n\tint__supply_chain__supplies__cost_analysis AS (\n\t\tSELECT\n\t\t\tstg__supply_chain__supplies__inventory.cost_cents,\n\t\t\tstg__supply_chain__supplies__inventory.cost_dollars,\n\t\t\t{{ cost_tier() }} AS cost_tier,\n\t\t\tstg__supply_chain__supplies__inventory.is_perishable,\n\t\t\tstg__supply_chain__supplies__inventory.portal_source_count,\n\t\t\tstg__products__catalog__catalog.product_name,\n\t\t\tstg__products__catalog__catalog.product_price_dollars,\n\t\t\tstg__supply_chain__supplies__inventory.product_sku,\n\t\t\tstg__products__catalog__catalog.product_type,\n\t\t\tstg__supply_chain__supplies__inventory.supply_category,\n\t\t\tstg__supply_chain__supplies__inventory.supply_id,\n\t\t\tstg__supply_chain__supplies__inventory.supply_name,\n\t\t\t{{ supply_to_price_ratio() }} AS supply_to_price_ratio\n\t\tFROM\n\t\t\t{{ ref('stg__supply_chain__supplies__inventory') }} stg__supply_chain__supplies__inventory\n\t\t\tLEFT JOIN {{ ref('stg__products__catalog__catalog') }} stg__products__catalog__catalog ON stg__supply_chain__supplies__inventory.product_sku = stg__products__catalog__catalog.product_sku\n\t)\nSELECT\n\t*\nFROM\n\tint__supply_chain__supplies__cost_analysis","doc_blocks":[],"language":"sql","refs":[{"name":"stg__supply_chain__supplies__inventory","package":null,"version":null},{"name":"stg__products__catalog__catalog","package":null,"version":null}],"sources":[],"metrics":[],"depends_on":{"macros":["macro.jaffle_shop.cost_tier","macro.jaffle_shop.supply_to_price_ratio"],"nodes":["model.jaffle_shop.stg__supply_chain__supplies__inventory","model.jaffle_shop.stg__products__catalog__catalog"]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"access":"protected","constraints":[],"version":null,"latest_version":null,"deprecation_date":null,"primary_key":[],"time_spine":null},"seed.jaffle_shop.raw_items":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_items","resource_type":"seed","package_name":"jaffle_shop","path":"raw_items.csv","original_file_path":"seeds/raw_items.csv","unique_id":"seed.jaffle_shop.raw_items","fqn":["jaffle_shop","raw_items"],"alias":"raw_items","checksum":{"name":"path","checksum":"seeds/raw_items.csv"},"config":{"enabled":true,"alias":null,"schema":"seeds","database":null,"tags":[],"meta":{},"group":null,"materialized":"seed","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"delimiter":",","quote_columns":false},"tags":[],"description":"","columns":{},"meta":{},"group":null,"docs":{"show":true,"node_color":null},"patch_path":null,"build_path":null,"unrendered_config":{"quote_columns":false,"schema":"seeds"},"created_at":1793083935.369601,"relation_name":"development.jaffle_shop_dev_seeds.raw_items","raw_code":"","doc_blocks":[],"root_path":"/path/to/dbt/project","depends_on":{"macros":[]}},"seed.jaffle_shop.raw_customers":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_customers","resource_type":"seed","package_name":"jaffle_shop","path":"raw_customers.csv","original_file_path":"seeds/raw_customers.csv","unique_id":"seed.jaffle_shop.raw_customers","fqn":["jaffle_shop","raw_customers"],"alias":"raw_customers","checksum":{"name":"sha256","checksum":"d91ca12deb29112b84ef9b56856fcb69645497bbca8315379dedf61b55b504b1"},"config":{"enabled":true,"alias":null,"schema":"seeds","database":null,"tags":[],"meta":{},"group":null,"materialized":"seed","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"delimiter":",","quote_columns":false},"tags":[],"description":"","columns":{},"meta":{},"group":null,"docs":{"show":true,"node_color":null},"patch_path":null,"build_path":null,"unrendered_config":{"quote_columns":false,"schema":"seeds"},"created_at":1793083935.370752,"relation_name":"development.jaffle_shop_dev_seeds.raw_customers","raw_code":"","doc_blocks":[],"root_path":"/path/to/dbt/project","depends_on":{"macros":[]}},"seed.jaffle_shop.raw_stores":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_stores","resource_type":"seed","package_name":"jaffle_shop","path":"raw_stores.csv","original_file_path":"seeds/raw_stores.csv","unique_id":"seed.jaffle_shop.raw_stores","fqn":["jaffle_shop","raw_stores"],"alias":"raw_stores","checksum":{"name":"sha256","checksum":"3766ca1319b55ea44a16296e24a5faefe26a182b85b0f5142c986482f9801ccc"},"config":{"enabled":true,"alias":null,"schema":"seeds","database":null,"tags":[],"meta":{},"group":null,"materialized":"seed","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"delimiter":",","quote_columns":false},"tags":[],"description":"","columns":{},"meta":{},"group":null,"docs":{"show":true,"node_color":null},"patch_path":null,"build_path":null,"unrendered_config":{"quote_columns":false,"schema":"seeds"},"created_at":1793083935.371695,"relation_name":"development.jaffle_shop_dev_seeds.raw_stores","raw_code":"","doc_blocks":[],"root_path":"/path/to/dbt/project","depends_on":{"macros":[]}},"seed.jaffle_shop.raw_orders":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_orders","resource_type":"seed","package_name":"jaffle_shop","path":"raw_orders.csv","original_file_path":"seeds/raw_orders.csv","unique_id":"seed.jaffle_shop.raw_orders","fqn":["jaffle_shop","raw_orders"],"alias":"raw_orders","checksum":{"name":"path","checksum":"seeds/raw_orders.csv"},"config":{"enabled":true,"alias":null,"schema":"seeds","database":null,"tags":[],"meta":{},"group":null,"materialized":"seed","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"delimiter":",","quote_columns":false},"tags":[],"description":"","columns":{},"meta":{},"group":null,"docs":{"show":true,"node_color":null},"patch_path":null,"build_path":null,"unrendered_config":{"quote_columns":false,"schema":"seeds"},"created_at":1793083935.372597,"relation_name":"development.jaffle_shop_dev_seeds.raw_orders","raw_code":"","doc_blocks":[],"root_path":"/path/to/dbt/project","depends_on":{"macros":[]}},"seed.jaffle_shop.raw_supplies":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_supplies","resource_type":"seed","package_name":"jaffle_shop","path":"raw_supplies.csv","original_file_path":"seeds/raw_supplies.csv","unique_id":"seed.jaffle_shop.raw_supplies","fqn":["jaffle_shop","raw_supplies"],"alias":"raw_supplies","checksum":{"name":"sha256","checksum":"da4dedefd0350e023054c208a20bda46ecc4b39e037b42be2ed4c39ed19ddf2d"},"config":{"enabled":true,"alias":null,"schema":"seeds","database":null,"tags":[],"meta":{},"group":null,"materialized":"seed","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"delimiter":",","quote_columns":false},"tags":[],"description":"","columns":{},"meta":{},"group":null,"docs":{"show":true,"node_color":null},"patch_path":null,"build_path":null,"unrendered_config":{"quote_columns":false,"schema":"seeds"},"created_at":1793083935.3734982,"relation_name":"development.jaffle_shop_dev_seeds.raw_supplies","raw_code":"","doc_blocks":[],"root_path":"/path/to/dbt/project","depends_on":{"macros":[]}},"seed.jaffle_shop.raw_products":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_products","resource_type":"seed","package_name":"jaffle_shop","path":"raw_products.csv","original_file_path":"seeds/raw_products.csv","unique_id":"seed.jaffle_shop.raw_products","fqn":["jaffle_shop","raw_products"],"alias":"raw_products","checksum":{"name":"sha256","checksum":"a272e2f54aea0708c26ea3d8fb0cc6062196b68c8e47ab6197426c7cd3f841d8"},"config":{"enabled":true,"alias":null,"schema":"seeds","database":null,"tags":[],"meta":{},"group":null,"materialized":"seed","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null,"delimiter":",","quote_columns":false},"tags":[],"description":"","columns":{},"meta":{},"group":null,"docs":{"show":true,"node_color":null},"patch_path":null,"build_path":null,"unrendered_config":{"quote_columns":false,"schema":"seeds"},"created_at":1793083935.374449,"relation_name":"development.jaffle_shop_dev_seeds.raw_products","raw_code":"","doc_blocks":[],"root_path":"/path/to/dbt/project","depends_on":{"macros":[]}},"operation.jaffle_shop.jaffle_shop-on-run-start-0":{"database":"development","schema":"jaffle_shop_dev","name":"jaffle_shop-on-run-start-0","resource_type":"operation","package_name":"jaffle_shop","path":"hooks/jaffle_shop-on-run-start-0.sql","original_file_path":"./dbt_project.yml","unique_id":"operation.jaffle_shop.jaffle_shop-on-run-start-0","fqn":["jaffle_shop","hooks","jaffle_shop-on-run-start-0"],"alias":"jaffle_shop-on-run-start-0","checksum":{"name":"sha256","checksum":"f4d5f4fec0c794219b54d382a7559fbbf9dc34179f018f10c31c6973d773da01"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":[],"meta":{},"group":null,"materialized":"view","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null},"tags":["on-run-start"],"description":"","columns":{},"meta":{},"group":null,"docs":{"show":true,"node_color":null},"patch_path":null,"build_path":null,"unrendered_config":{},"created_at":1793083935.440772,"relation_name":null,"raw_code":"{{ log('Run started: ' ~ run_started_at, info=True) }}","doc_blocks":[],"language":"sql","refs":[],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":[]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"index":0},"operation.jaffle_shop.jaffle_shop-on-run-end-0":{"database":"development","schema":"jaffle_shop_dev","name":"jaffle_shop-on-run-end-0","resource_type":"operation","package_name":"jaffle_shop","path":"hooks/jaffle_shop-on-run-end-0.sql","original_file_path":"./dbt_project.yml","unique_id":"operation.jaffle_shop.jaffle_shop-on-run-end-0","fqn":["jaffle_shop","hooks","jaffle_shop-on-run-end-0"],"alias":"jaffle_shop-on-run-end-0","checksum":{"name":"sha256","checksum":"f4d5f4fec0c794219b54d382a7559fbbf9dc34179f018f10c31c6973d773da01"},"config":{"enabled":true,"alias":null,"schema":null,"database":null,"tags":[],"meta":{},"group":null,"materialized":"view","incremental_strategy":null,"batch_size":null,"lookback":1,"begin":null,"persist_docs":{},"post-hook":[],"pre-hook":[],"quoting":{},"column_types":{},"full_refresh":null,"unique_key":null,"on_schema_change":"ignore","on_configuration_change":"apply","grants":{},"packages":[],"docs":{"show":true,"node_color":null},"contract":{"enforced":false,"alias_types":true},"event_time":null,"concurrent_batches":null},"tags":["on-run-end"],"description":"","columns":{},"meta":{},"group":null,"docs":{"show":true,"node_color":null},"patch_path":null,"build_path":null,"unrendered_config":{},"created_at":1793083935.446573,"relation_name":null,"raw_code":"{{ log('Run finished: ' ~ run_finished_at, info=True) }}","doc_blocks":[],"language":"sql","refs":[],"sources":[],"metrics":[],"depends_on":{"macros":[],"nodes":[]},"compiled_path":null,"contract":{"enforced":false,"alias_types":true,"checksum":null},"index":0}},"sources":{"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_customers":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_customers","resource_type":"source","package_name":"jaffle_shop","path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","original_file_path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","unique_id":"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_customers","fqn":["jaffle_shop","sources","development","development__jaffle_shop_dev_seeds","raw_customers"],"source_name":"development__jaffle_shop_dev_seeds","source_description":"","loader":"","identifier":"raw_customers","quoting":{"database":null,"schema":null,"identifier":null,"column":null},"loaded_at_field":null,"loaded_at_query":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"external":null,"description":"","columns":{"id":{"name":"id","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"name":{"name":"name","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"source_meta":{},"tags":[],"config":{"enabled":true,"event_time":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"patch_path":null,"unrendered_config":{"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"relation_name":"development.jaffle_shop_dev_seeds.raw_customers","created_at":1793083935.6579788,"unrendered_database":"development","unrendered_schema":"jaffle_shop_dev_seeds","doc_blocks":[]},"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_items":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_items","resource_type":"source","package_name":"jaffle_shop","path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","original_file_path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","unique_id":"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_items","fqn":["jaffle_shop","sources","development","development__jaffle_shop_dev_seeds","raw_items"],"source_name":"development__jaffle_shop_dev_seeds","source_description":"","loader":"","identifier":"raw_items","quoting":{"database":null,"schema":null,"identifier":null,"column":null},"loaded_at_field":null,"loaded_at_query":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"external":null,"description":"","columns":{"id":{"name":"id","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_id":{"name":"order_id","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"sku":{"name":"sku","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"source_meta":{},"tags":[],"config":{"enabled":true,"event_time":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"patch_path":null,"unrendered_config":{"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"relation_name":"development.jaffle_shop_dev_seeds.raw_items","created_at":1793083935.658786,"unrendered_database":"development","unrendered_schema":"jaffle_shop_dev_seeds","doc_blocks":[]},"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_orders":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_orders","resource_type":"source","package_name":"jaffle_shop","path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","original_file_path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","unique_id":"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_orders","fqn":["jaffle_shop","sources","development","development__jaffle_shop_dev_seeds","raw_orders"],"source_name":"development__jaffle_shop_dev_seeds","source_description":"","loader":"","identifier":"raw_orders","quoting":{"database":null,"schema":null,"identifier":null,"column":null},"loaded_at_field":null,"loaded_at_query":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"external":null,"description":"","columns":{"id":{"name":"id","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"customer":{"name":"customer","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"ordered_at":{"name":"ordered_at","description":"","meta":{},"data_type":"timestamp(3)","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"store_id":{"name":"store_id","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"subtotal":{"name":"subtotal","description":"","meta":{},"data_type":"integer","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"tax_paid":{"name":"tax_paid","description":"","meta":{},"data_type":"integer","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"order_total":{"name":"order_total","description":"","meta":{},"data_type":"integer","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"source_meta":{},"tags":[],"config":{"enabled":true,"event_time":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"patch_path":null,"unrendered_config":{"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"relation_name":"development.jaffle_shop_dev_seeds.raw_orders","created_at":1793083935.659053,"unrendered_database":"development","unrendered_schema":"jaffle_shop_dev_seeds","doc_blocks":[]},"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_products":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_products","resource_type":"source","package_name":"jaffle_shop","path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","original_file_path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","unique_id":"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_products","fqn":["jaffle_shop","sources","development","development__jaffle_shop_dev_seeds","raw_products"],"source_name":"development__jaffle_shop_dev_seeds","source_description":"","loader":"","identifier":"raw_products","quoting":{"database":null,"schema":null,"identifier":null,"column":null},"loaded_at_field":null,"loaded_at_query":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"external":null,"description":"","columns":{"sku":{"name":"sku","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"name":{"name":"name","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"type":{"name":"type","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"price":{"name":"price","description":"","meta":{},"data_type":"integer","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"description":{"name":"description","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"source_meta":{},"tags":[],"config":{"enabled":true,"event_time":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"patch_path":null,"unrendered_config":{"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"relation_name":"development.jaffle_shop_dev_seeds.raw_products","created_at":1793083935.659297,"unrendered_database":"development","unrendered_schema":"jaffle_shop_dev_seeds","doc_blocks":[]},"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_stores":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_stores","resource_type":"source","package_name":"jaffle_shop","path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","original_file_path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","unique_id":"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_stores","fqn":["jaffle_shop","sources","development","development__jaffle_shop_dev_seeds","raw_stores"],"source_name":"development__jaffle_shop_dev_seeds","source_description":"","loader":"","identifier":"raw_stores","quoting":{"database":null,"schema":null,"identifier":null,"column":null},"loaded_at_field":null,"loaded_at_query":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"external":null,"description":"","columns":{"id":{"name":"id","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"name":{"name":"name","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"opened_at":{"name":"opened_at","description":"","meta":{},"data_type":"timestamp(3)","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"tax_rate":{"name":"tax_rate","description":"","meta":{},"data_type":"double","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"source_meta":{},"tags":[],"config":{"enabled":true,"event_time":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"patch_path":null,"unrendered_config":{"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"relation_name":"development.jaffle_shop_dev_seeds.raw_stores","created_at":1793083935.659629,"unrendered_database":"development","unrendered_schema":"jaffle_shop_dev_seeds","doc_blocks":[]},"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_supplies":{"database":"development","schema":"jaffle_shop_dev_seeds","name":"raw_supplies","resource_type":"source","package_name":"jaffle_shop","path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","original_file_path":"models/sources/development/development__jaffle_shop_dev_seeds.yml","unique_id":"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_supplies","fqn":["jaffle_shop","sources","development","development__jaffle_shop_dev_seeds","raw_supplies"],"source_name":"development__jaffle_shop_dev_seeds","source_description":"","loader":"","identifier":"raw_supplies","quoting":{"database":null,"schema":null,"identifier":null,"column":null},"loaded_at_field":null,"loaded_at_query":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"external":null,"description":"","columns":{"id":{"name":"id","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"name":{"name":"name","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"cost":{"name":"cost","description":"","meta":{},"data_type":"integer","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"perishable":{"name":"perishable","description":"","meta":{},"data_type":"boolean","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]},"sku":{"name":"sku","description":"","meta":{},"data_type":"varchar","constraints":[],"quote":null,"config":{"meta":{},"tags":[]},"tags":[],"granularity":null,"doc_blocks":[]}},"meta":{},"source_meta":{},"tags":[],"config":{"enabled":true,"event_time":null,"freshness":{"warn_after":{"count":null,"period":null},"error_after":{"count":null,"period":null},"filter":null},"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"patch_path":null,"unrendered_config":{"loaded_at_field":null,"loaded_at_query":null,"meta":{},"tags":[]},"relation_name":"development.jaffle_shop_dev_seeds.raw_supplies","created_at":1793083935.6598651,"unrendered_database":"development","unrendered_schema":"jaffle_shop_dev_seeds","doc_blocks":[]}},"docs":{"doc.dbt.__overview__":{"name":"__overview__","resource_type":"doc","package_name":"dbt","path":"overview.md","original_file_path":"docs/overview.md","unique_id":"doc.dbt.__overview__","block_contents":"### Welcome!\n\nWelcome to the auto-generated documentation for your dbt project!\n\n### Navigation\n\nYou can use the `Project` and `Database` navigation tabs on the left side of the window to explore the models\nin your project.\n\n#### Project Tab\nThe `Project` tab mirrors the directory structure of your dbt project. In this tab, you can see all of the\nmodels defined in your dbt project, as well as models imported from dbt packages.\n\n#### Database Tab\nThe `Database` tab also exposes your models, but in a format that looks more like a database explorer. This view\nshows relations (tables and views) grouped into database schemas. Note that ephemeral models are _not_ shown\nin this interface, as they do not exist in the database.\n\n### Graph Exploration\nYou can click the blue icon on the bottom-right corner of the page to view the lineage graph of your models.\n\nOn model pages, you'll see the immediate parents and children of the model you're exploring. By clicking the `Expand`\nbutton at the top-right of this lineage pane, you'll be able to see all of the models that are used to build,\nor are built from, the model you're exploring.\n\nOnce expanded, you'll be able to use the `--select` and `--exclude` model selection syntax to filter the\nmodels in the graph. For more information on model selection, check out the [dbt docs](https://docs.getdbt.com/docs/model-selection-syntax).\n\nNote that you can also right-click on models to interactively filter and explore the graph.\n\n---\n\n### More information\n\n- [What is dbt](https://docs.getdbt.com/docs/introduction)?\n- Read the [dbt viewpoint](https://docs.getdbt.com/docs/viewpoint)\n- [Installation](https://docs.getdbt.com/docs/installation)\n- Join the [dbt Community](https://www.getdbt.com/community/) for questions and discussion"}},"exposures":{},"metrics":{},"groups":{"group.jaffle_shop.sales":{"name":"sales","resource_type":"group","package_name":"jaffle_shop","path":"groups.yml","original_file_path":"models/groups.yml","unique_id":"group.jaffle_shop.sales","owner":{"email":"sales@example.com","name":"Sales Team"},"description":"Order processing, revenue tracking, profitability analysis, and sales performance metrics","config":{"meta":{}}},"group.jaffle_shop.products":{"name":"products","resource_type":"group","package_name":"jaffle_shop","path":"groups.yml","original_file_path":"models/groups.yml","unique_id":"group.jaffle_shop.products","owner":{"email":"product@example.com","name":"Product Team"},"description":"Product catalog management, menu analytics, cost efficiency analysis, and supply chain optimization","config":{"meta":{}}},"group.jaffle_shop.customers":{"name":"customers","resource_type":"group","package_name":"jaffle_shop","path":"groups.yml","original_file_path":"models/groups.yml","unique_id":"group.jaffle_shop.customers","owner":{"email":"customers@example.com","name":"Customer Team"},"description":"Customer profiles, behavior analysis, segmentation, and customer-focused dashboards","config":{"meta":{}}},"group.jaffle_shop.supply_chain":{"name":"supply_chain","resource_type":"group","package_name":"jaffle_shop","path":"groups.yml","original_file_path":"models/groups.yml","unique_id":"group.jaffle_shop.supply_chain","owner":{"email":"supply-chain@example.com","name":"Supply Chain Team"},"description":"Supply cost analysis, inventory management, and supplier performance tracking","config":{"meta":{}}},"group.jaffle_shop.analytics":{"name":"analytics","resource_type":"group","package_name":"jaffle_shop","path":"groups.yml","original_file_path":"models/groups.yml","unique_id":"group.jaffle_shop.analytics","owner":{"email":"analytics@example.com","name":"Analytics Team"},"description":"Cross-functional business intelligence, comprehensive analytics, and strategic insights across all business areas","config":{"meta":{}}}},"selectors":{},"disabled":{},"parent_map":{"model.jaffle_shop.stg__customers__profiles__clean":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_customers"],"model.jaffle_shop.stg__products__catalog__catalog":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_products"],"model.jaffle_shop.stg__sales__stores__locations":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_stores"],"model.jaffle_shop.stg__sales__orders__standardized":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_orders"],"model.jaffle_shop.stg__sales__items__order_details":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_items"],"model.jaffle_shop.stg__supply_chain__supplies__inventory":["source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_supplies"],"model.jaffle_shop.mart__customers__dashboard__analytics":["model.jaffle_shop.int__customers__profiles__summary"],"model.jaffle_shop.mart__products__reporting__cost_efficiency":["model.jaffle_shop.int__supply_chain__supplies__cost_analysis"],"model.jaffle_shop.mart__products__reporting__menu_analytics":["model.jaffle_shop.int__products__analytics__product_popularity"],"model.jaffle_shop.mart__sales__reporting__revenue":["model.jaffle_shop.int__sales__orders__enriched"],"model.jaffle_shop.mart__sales__reporting__profitability":["model.jaffle_shop.int__sales__orders__enriched"],"model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics":["model.jaffle_shop.mart__products__reporting__cost_efficiency","model.jaffle_shop.mart__products__reporting__menu_analytics"],"model.jaffle_shop.int__customers__profiles__summary":["model.jaffle_shop.stg__customers__profiles__clean","model.jaffle_shop.stg__sales__orders__standardized"],"model.jaffle_shop.int__products__analytics__product_popularity":["model.jaffle_shop.stg__sales__items__order_details"],"model.jaffle_shop.int__sales__orders__enriched":["model.jaffle_shop.stg__customers__profiles__clean","model.jaffle_shop.stg__sales__orders__standardized","model.jaffle_shop.stg__sales__stores__locations"],"model.jaffle_shop.int__sales__orders__regional_combined":["model.jaffle_shop.int__sales__orders__enriched"],"model.jaffle_shop.int__sales__analytics__rolling_30day":["model.jaffle_shop.int__sales__orders__enriched"],"model.jaffle_shop.int__sales__analytics__monthly_revenue":["model.jaffle_shop.int__sales__orders__enriched"],"model.jaffle_shop.int__supply_chain__supplies__cost_analysis":["model.jaffle_shop.stg__products__catalog__catalog","model.jaffle_shop.stg__supply_chain__supplies__inventory"],"seed.jaffle_shop.raw_items":[],"seed.jaffle_shop.raw_customers":[],"seed.jaffle_shop.raw_stores":[],"seed.jaffle_shop.raw_orders":[],"seed.jaffle_shop.raw_supplies":[],"seed.jaffle_shop.raw_products":[],"operation.jaffle_shop.jaffle_shop-on-run-start-0":[],"operation.jaffle_shop.jaffle_shop-on-run-end-0":[],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_customers":[],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_items":[],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_orders":[],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_products":[],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_stores":[],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_supplies":[]},"child_map":{"model.jaffle_shop.stg__customers__profiles__clean":["model.jaffle_shop.int__customers__profiles__summary","model.jaffle_shop.int__sales__orders__enriched"],"model.jaffle_shop.stg__products__catalog__catalog":["model.jaffle_shop.int__supply_chain__supplies__cost_analysis"],"model.jaffle_shop.stg__sales__stores__locations":["model.jaffle_shop.int__sales__orders__enriched"],"model.jaffle_shop.stg__sales__orders__standardized":["model.jaffle_shop.int__customers__profiles__summary","model.jaffle_shop.int__sales__orders__enriched"],"model.jaffle_shop.stg__sales__items__order_details":["model.jaffle_shop.int__products__analytics__product_popularity"],"model.jaffle_shop.stg__supply_chain__supplies__inventory":["model.jaffle_shop.int__supply_chain__supplies__cost_analysis"],"model.jaffle_shop.mart__customers__dashboard__analytics":[],"model.jaffle_shop.mart__products__reporting__cost_efficiency":["model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics"],"model.jaffle_shop.mart__products__reporting__menu_analytics":["model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics"],"model.jaffle_shop.mart__sales__reporting__revenue":[],"model.jaffle_shop.mart__sales__reporting__profitability":[],"model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics":[],"model.jaffle_shop.int__customers__profiles__summary":["model.jaffle_shop.mart__customers__dashboard__analytics"],"model.jaffle_shop.int__products__analytics__product_popularity":["model.jaffle_shop.mart__products__reporting__menu_analytics"],"model.jaffle_shop.int__sales__orders__enriched":["model.jaffle_shop.int__sales__analytics__monthly_revenue","model.jaffle_shop.int__sales__analytics__rolling_30day","model.jaffle_shop.int__sales__orders__regional_combined","model.jaffle_shop.mart__sales__reporting__profitability","model.jaffle_shop.mart__sales__reporting__revenue"],"model.jaffle_shop.int__sales__orders__regional_combined":[],"model.jaffle_shop.int__sales__analytics__rolling_30day":[],"model.jaffle_shop.int__sales__analytics__monthly_revenue":[],"model.jaffle_shop.int__supply_chain__supplies__cost_analysis":["model.jaffle_shop.mart__products__reporting__cost_efficiency"],"seed.jaffle_shop.raw_items":[],"seed.jaffle_shop.raw_customers":[],"seed.jaffle_shop.raw_stores":[],"seed.jaffle_shop.raw_orders":[],"seed.jaffle_shop.raw_supplies":[],"seed.jaffle_shop.raw_products":[],"operation.jaffle_shop.jaffle_shop-on-run-start-0":[],"operation.jaffle_shop.jaffle_shop-on-run-end-0":[],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_customers":["model.jaffle_shop.stg__customers__profiles__clean"],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_items":["model.jaffle_shop.stg__sales__items__order_details"],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_orders":["model.jaffle_shop.stg__sales__orders__standardized"],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_products":["model.jaffle_shop.stg__products__catalog__catalog"],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_stores":["model.jaffle_shop.stg__sales__stores__locations"],"source.jaffle_shop.development__jaffle_shop_dev_seeds.raw_supplies":["model.jaffle_shop.stg__supply_chain__supplies__inventory"]},"group_map":{"sales":["model.jaffle_shop.stg__sales__stores__locations","model.jaffle_shop.stg__sales__orders__standardized","model.jaffle_shop.stg__sales__items__order_details","model.jaffle_shop.mart__sales__reporting__revenue","model.jaffle_shop.mart__sales__reporting__profitability","model.jaffle_shop.int__sales__orders__enriched","model.jaffle_shop.int__sales__orders__regional_combined","model.jaffle_shop.int__sales__analytics__rolling_30day","model.jaffle_shop.int__sales__analytics__monthly_revenue"],"products":["model.jaffle_shop.stg__products__catalog__catalog","model.jaffle_shop.mart__products__reporting__cost_efficiency","model.jaffle_shop.mart__products__reporting__menu_analytics","model.jaffle_shop.int__products__analytics__product_popularity"],"customers":["model.jaffle_shop.stg__customers__profiles__clean","model.jaffle_shop.mart__customers__dashboard__analytics","model.jaffle_shop.int__customers__profiles__summary"],"supply_chain":["model.jaffle_shop.stg__supply_chain__supplies__inventory","model.jaffle_shop.int__supply_chain__supplies__cost_analysis"],"analytics":["model.jaffle_shop.mart__analytics__dashboard__comprehensive_analytics"]},"saved_queries":{},"semantic_models":{},"unit_tests":{}} \ No newline at end of file diff --git a/tests/fixtures/stg__customers__profiles__clean.model.json b/tests/fixtures/stg__customers__profiles__clean.model.json index 5eb44fc..7bcd69c 100644 --- a/tests/fixtures/stg__customers__profiles__clean.model.json +++ b/tests/fixtures/stg__customers__profiles__clean.model.json @@ -3,7 +3,7 @@ "group": "customers", "topic": "profiles", "name": "clean", - "materialized": "ephemeral", + "materialization": "ephemeral", "from": { "source": "development__jaffle_shop_dev_seeds.raw_customers" }, diff --git a/tests/fixtures/stg__products__catalog__catalog.model.json b/tests/fixtures/stg__products__catalog__catalog.model.json index dd5dbde..4917810 100644 --- a/tests/fixtures/stg__products__catalog__catalog.model.json +++ b/tests/fixtures/stg__products__catalog__catalog.model.json @@ -3,7 +3,7 @@ "group": "products", "topic": "catalog", "name": "catalog", - "materialized": "ephemeral", + "materialization": "ephemeral", "from": { "source": "development__jaffle_shop_dev_seeds.raw_products" }, diff --git a/tests/fixtures/stg__sales__items__order_details.model.json b/tests/fixtures/stg__sales__items__order_details.model.json index a7a0658..41bd159 100644 --- a/tests/fixtures/stg__sales__items__order_details.model.json +++ b/tests/fixtures/stg__sales__items__order_details.model.json @@ -3,7 +3,7 @@ "group": "sales", "topic": "items", "name": "order_details", - "materialized": "ephemeral", + "materialization": "ephemeral", "from": { "source": "development__jaffle_shop_dev_seeds.raw_items" }, diff --git a/tests/fixtures/stg__sales__orders__standardized.model.json b/tests/fixtures/stg__sales__orders__standardized.model.json index 94a1941..9f05c63 100644 --- a/tests/fixtures/stg__sales__orders__standardized.model.json +++ b/tests/fixtures/stg__sales__orders__standardized.model.json @@ -3,7 +3,7 @@ "group": "sales", "topic": "orders", "name": "standardized", - "materialized": "ephemeral", + "materialization": "ephemeral", "from": { "source": "development__jaffle_shop_dev_seeds.raw_orders" }, diff --git a/tests/fixtures/stg__sales__stores__locations.model.json b/tests/fixtures/stg__sales__stores__locations.model.json index b1f2537..1f7fbac 100644 --- a/tests/fixtures/stg__sales__stores__locations.model.json +++ b/tests/fixtures/stg__sales__stores__locations.model.json @@ -3,7 +3,7 @@ "group": "sales", "topic": "stores", "name": "locations", - "materialized": "ephemeral", + "materialization": "ephemeral", "from": { "source": "development__jaffle_shop_dev_seeds.raw_stores" }, diff --git a/tests/fixtures/stg__supply_chain__supplies__inventory.model.json b/tests/fixtures/stg__supply_chain__supplies__inventory.model.json index 8bd8f90..5cf46a6 100644 --- a/tests/fixtures/stg__supply_chain__supplies__inventory.model.json +++ b/tests/fixtures/stg__supply_chain__supplies__inventory.model.json @@ -3,7 +3,7 @@ "group": "supply_chain", "topic": "supplies", "name": "inventory", - "materialized": "ephemeral", + "materialization": "ephemeral", "from": { "source": "development__jaffle_shop_dev_seeds.raw_supplies" }, diff --git a/web/src/context/app.tsx b/web/src/context/app.tsx index bc9afe3..670eb87 100644 --- a/web/src/context/app.tsx +++ b/web/src/context/app.tsx @@ -1898,7 +1898,10 @@ SELECT * FROM final`, return resolve(apiResponse([])); case 'framework-model-create-batch': return resolve( - apiResponse({ phase: 'done', results: [] }), + apiResponse({ + phase: 'done', + results: [], + }), ); case 'framework-model-columns': return resolve( diff --git a/web/src/features/ModelWizard/AdditionalFields.tsx b/web/src/features/ModelWizard/AdditionalFields.tsx index 6054887..c2a73e9 100644 --- a/web/src/features/ModelWizard/AdditionalFields.tsx +++ b/web/src/features/ModelWizard/AdditionalFields.tsx @@ -1,4 +1,8 @@ -import { FRAMEWORK_PARTITIONS } from '@shared/framework/constants'; +import { + DEFAULT_INCREMENTAL_PRE_HOOK, + DEFAULT_INCREMENTAL_STRATEGY, + FRAMEWORK_PARTITIONS, +} from '@shared/framework/constants'; import type { IncrementalStrategy } from '@shared/schema/types/model.schema'; import { Checkbox, @@ -65,8 +69,13 @@ export function AdditionalFields({ watch, }: AdditionalFieldsProps) { const type = useModelStore((state) => state.basicFields.type); - const materialized = useModelStore((state) => state.basicFields.materialized); + const materialization = useModelStore( + (state) => state.basicFields.materialization, + ); const setAdditionalField = useModelStore((state) => state.setAdditionalField); + const defaultIncrementalStrategy = + useModelStore((state) => state.defaultIncrementalStrategy) ?? + DEFAULT_INCREMENTAL_STRATEGY; const additionalFieldsSqlHooks = useModelStore( (state) => state.additionalFields.sql_hooks, ); @@ -77,7 +86,7 @@ export function AdditionalFields({ | undefined; // Sync store's sql_hooks to form state on mount - // This handles cases where materialized was changed on BasicInformation step, + // This handles cases where materialization was changed on BasicInformation step, // updating sql_hooks in the store, and user navigates to AdditionalFields step useEffect(() => { const formHooks = watch('sql_hooks'); @@ -98,7 +107,7 @@ export function AdditionalFields({ type, ); - const isIncrementalMaterialization = materialized === 'incremental'; + const isIncrementalMaterialization = materialization === 'incremental'; /** * Exclude daily filters are not available for stg_select_source, stg_union_sources and mart models @@ -108,7 +117,7 @@ export function AdditionalFields({ ); /** - * Incremental Strategy is only available when materialized type is 'incremental' and non-mart model + * Incremental Strategy is only available when materialization type is 'incremental' and non-mart model */ const showIncrementalStrategy = !isMartModelType && isIncrementalMaterialization; @@ -142,23 +151,36 @@ export function AdditionalFields({ self.findIndex((s) => s.trim() === stmt.trim()) === index, ); - const hookValue: string | [string, ...string[]] | undefined = - uniqueStatements.length === 0 + const hookValue: string | [string, ...string[]] | null | undefined = + hookType === 'pre' && + uniqueStatements.length === 1 && + uniqueStatements[0] === DEFAULT_INCREMENTAL_PRE_HOOK ? undefined - : uniqueStatements.length === 1 - ? uniqueStatements[0] - : (uniqueStatements as [string, ...string[]]); - - const newSqlHooks = { + : uniqueStatements.length === 0 + ? hookType === 'pre' && materialization === 'incremental' + ? null + : undefined + : uniqueStatements.length === 1 + ? uniqueStatements[0] + : (uniqueStatements as [string, ...string[]]); + + const newSqlHooks: ModelWizardFormValues['sql_hooks'] = { ...currentSqlHooks, [hookType]: hookValue, }; - - fieldOnChange(newSqlHooks); - setValue('sql_hooks', newSqlHooks); - setAdditionalField('sql_hooks', newSqlHooks); + if (hookValue === undefined) { + delete newSqlHooks[hookType]; + } + const stored = + newSqlHooks.pre !== undefined || newSqlHooks.post !== undefined + ? newSqlHooks + : undefined; + + fieldOnChange(stored); + setValue('sql_hooks', stored); + setAdditionalField('sql_hooks', stored); }, - [setValue, setAdditionalField], + [materialization, setAdditionalField, setValue], ); return ( @@ -230,12 +252,37 @@ export function AdditionalFields({ name={field.name} onBlur={field.onBlur} value={field.value || ''} + placeholder={`Default (${defaultIncrementalStrategy})`} onChange={(value) => { - field.onChange(value); - const updateIncrementalStrategy = { - ...incrementalStrategy, - type: value as IncrementalStrategy['type'], - } as IncrementalStrategy; + if (!value) { + field.onChange(undefined); + setValue('incremental_strategy', undefined); + setAdditionalField('incremental_strategy', undefined); + return; + } + const strategyType = value as IncrementalStrategy['type']; + field.onChange(strategyType); + const previousKey = + incrementalStrategy && + 'unique_key' in incrementalStrategy && + incrementalStrategy.unique_key + ? incrementalStrategy.unique_key + : undefined; + const updateIncrementalStrategy = ( + strategyType === 'merge' + ? { + type: 'merge', + ...(previousKey ? { unique_key: previousKey } : {}), + } + : strategyType === 'delete+insert' + ? { + type: 'delete+insert', + ...(previousKey + ? { unique_key: previousKey } + : {}), + } + : { type: strategyType } + ) as IncrementalStrategy; setValue('incremental_strategy', updateIncrementalStrategy); setAdditionalField( 'incremental_strategy', @@ -308,17 +355,31 @@ export function AdditionalFields({ : (value as [string, ...string[]]); field.onChange(uniqueKeyValue); - const newStrategy = { - ...incrementalStrategy, - unique_key: uniqueKeyValue || '', - }; - setValue( - 'incremental_strategy', - newStrategy as ModelWizardFormValues['incremental_strategy'], - ); + const strategyType = incrementalStrategy?.type; + const newStrategy = ( + strategyType === 'merge' + ? { + type: 'merge', + ...(uniqueKeyValue + ? { unique_key: uniqueKeyValue } + : {}), + } + : strategyType === 'delete+insert' + ? { + type: 'delete+insert', + ...(uniqueKeyValue + ? { unique_key: uniqueKeyValue } + : {}), + } + : incrementalStrategy + ) as IncrementalStrategy | undefined; + if (!newStrategy) { + return; + } + setValue('incremental_strategy', newStrategy); setAdditionalField( 'incremental_strategy', - newStrategy as IncrementalStrategy, + newStrategy, ); }} onBlur={field.onBlur} @@ -446,17 +507,28 @@ export function AdditionalFields({ // Convert pre to array format const preValue = sqlHooks?.pre; - const preStatements = Array.isArray(preValue) - ? preValue - : preValue - ? [preValue] - : []; + const preStatements = + preValue === null + ? [] + : Array.isArray(preValue) + ? preValue + : preValue + ? [preValue] + : isIncrementalMaterialization + ? [DEFAULT_INCREMENTAL_PRE_HOOK] + : []; return (

Pre Hook - +

diff --git a/web/src/features/ModelWizard/BasicInformation.tsx b/web/src/features/ModelWizard/BasicInformation.tsx index 56e4a5e..390d622 100644 --- a/web/src/features/ModelWizard/BasicInformation.tsx +++ b/web/src/features/ModelWizard/BasicInformation.tsx @@ -28,7 +28,7 @@ interface BasicInformationProps { sourceOptions: Array<{ label: string; value: string }>; typeOptions: Array<{ label: string; value: string }>; groupOptions: Array<{ label: string; value: string }>; - materializedOptions: Array<{ label: string; value: string }>; + materializationOptions: Array<{ label: string; value: string }>; project: DbtProject | null; setProject: (project: DbtProject | null) => void; source: string; @@ -49,7 +49,7 @@ export function BasicInformation({ sourceOptions, typeOptions, groupOptions, - materializedOptions, + materializationOptions, project, setProject: _setProject, // Available for updating project state when needed source, @@ -126,7 +126,7 @@ export function BasicInformation({ // Clear the name so user can provide a new one name: '', topic: '', - materialized: undefined, + materialization: undefined, // Flag to indicate this is a clone operation isCloningModel: true, // Store the source model name for display @@ -294,11 +294,11 @@ export function BasicInformation({ // Reset type when source changes as the available types will change setValue('type', ''); // Reset to empty so user has to select again setBasicField('type', ''); - // Clear materialized field if switching to marts or staging (where it's hidden) + // Clear materialization field if switching to marts or staging (where it's hidden) if (newVal === 'marts' || newVal === 'staging') { - setValue('materialized', undefined); - setBasicField('materialized', ''); - void handleFieldChange('materialized', ''); + setValue('materialization', undefined); + setBasicField('materialization', ''); + void handleFieldChange('materialization', ''); } // Clear modeling state when source changes clearModelingState(); @@ -467,26 +467,26 @@ export function BasicInformation({ {/* File Name Preview */} {source && } - {/* 7. Materialized - dropdown - Hidden for marts and staging, optional for intermediate sources */} + {/* 7. Materialization - dropdown - Hidden for marts and staging, optional for intermediate sources */} {source === 'intermediate' && ( ( -
+
{ field.onChange(val); - setValue('materialized', val); - setBasicField('materialized', val as string); - void handleFieldChange('materialized', val as string); + setValue('materialization', val); + setBasicField('materialization', val as string); + void handleFieldChange('materialization', val as string); }} />
diff --git a/web/src/features/ModelWizard/mock/editFlowTestData.ts b/web/src/features/ModelWizard/mock/editFlowTestData.ts index 4abd744..62985e3 100644 --- a/web/src/features/ModelWizard/mock/editFlowTestData.ts +++ b/web/src/features/ModelWizard/mock/editFlowTestData.ts @@ -44,7 +44,7 @@ export const mockJoinModelData = { source: 'intermediate', description: 'this is a sample description', tags: ['lightdash'], - materialized: 'incremental', + materialization: 'incremental', from: { model: 'stg__demo__models__deployments', join: [ @@ -157,7 +157,7 @@ export const mockLookbackModelData = { group: 'analytics', topic: 'test', name: 'sample', - materialized: 'incremental', + materialization: 'incremental', description: 'this is a updated description', tags: ['lightdash-explore'], type: 'int_lookback_model', @@ -239,7 +239,7 @@ export const mockUnionSourcesModelData = { include: ['test', 'test2'], }, ], - materialized: 'ephemeral', + materialization: 'ephemeral', }, editFormType: 'model-stg__demo__cloud__demo_union_sources', isEditMode: true, diff --git a/web/src/features/ModelWizard/types.ts b/web/src/features/ModelWizard/types.ts index c0a9739..bf143dd 100644 --- a/web/src/features/ModelWizard/types.ts +++ b/web/src/features/ModelWizard/types.ts @@ -7,6 +7,6 @@ import type { AdditionalFieldsSchema } from '@web/stores/useModelStore'; */ export type ModelWizardFormValues = Api<'framework-model-create'>['request'] & { source?: string; - materialized?: string; + materialization?: string; cloneModel?: string; } & AdditionalFieldsSchema; diff --git a/web/src/features/Tutorial/config/assistMe/assistSteps.ts b/web/src/features/Tutorial/config/assistMe/assistSteps.ts index c64b628..3ccbea3 100644 --- a/web/src/features/Tutorial/config/assistMe/assistSteps.ts +++ b/web/src/features/Tutorial/config/assistMe/assistSteps.ts @@ -18,7 +18,7 @@ export enum DataModelingGuideStep { GROUP = 'group', TOPIC = 'topic', MODEL_NAME = 'model-name', - MATERIALIZED = 'materialized', + MATERIALIZATION = 'materialization', // Canvas Overview DATA_MODELING_INTRO = 'data-modeling-intro', @@ -66,7 +66,7 @@ export interface ModelState { type?: string; group?: string; topic?: string; - materialized?: string; + materialization?: string; fromModel?: string; fromSource?: string; hasJoins?: boolean; @@ -211,10 +211,10 @@ const ASSIST_RULES: AssistRule[] = [ requiresWizardAdvance: (state: ModelState) => state.source === 'staging', }, { - id: DataModelingGuideStep.MATERIALIZED, - element: '[data-tutorial-id="materialized-select"]', + id: DataModelingGuideStep.MATERIALIZATION, + element: '[data-tutorial-id="materialization-select"]', when: (state) => state.source === 'intermediate', - isCompleted: (state) => !!state.materialized, + isCompleted: (state) => !!state.materialization, popover: { title: 'Choose Materialization ⚙️', description: diff --git a/web/src/features/Tutorial/config/playTutorial/joinModelSteps.ts b/web/src/features/Tutorial/config/playTutorial/joinModelSteps.ts index f98df76..964aa2f 100644 --- a/web/src/features/Tutorial/config/playTutorial/joinModelSteps.ts +++ b/web/src/features/Tutorial/config/playTutorial/joinModelSteps.ts @@ -91,7 +91,7 @@ export const joinModelSteps: TutorialStep[] = [ wizardStep: 0, }, { - element: '[data-tutorial-id="materialized-select"]', + element: '[data-tutorial-id="materialization-select"]', popover: { title: 'Materialization', description: diff --git a/web/src/features/Tutorial/config/playTutorial/lookbackModelSteps.ts b/web/src/features/Tutorial/config/playTutorial/lookbackModelSteps.ts index 03f5ed7..75ea273 100644 --- a/web/src/features/Tutorial/config/playTutorial/lookbackModelSteps.ts +++ b/web/src/features/Tutorial/config/playTutorial/lookbackModelSteps.ts @@ -91,7 +91,7 @@ export const lookbackModelSteps: TutorialStep[] = [ wizardStep: 0, }, { - element: '[data-tutorial-id="materialized-select"]', + element: '[data-tutorial-id="materialization-select"]', popover: { title: 'Materialization', description: diff --git a/web/src/features/Tutorial/config/playTutorial/rollupModelSteps.ts b/web/src/features/Tutorial/config/playTutorial/rollupModelSteps.ts index 988dbc8..a79a714 100644 --- a/web/src/features/Tutorial/config/playTutorial/rollupModelSteps.ts +++ b/web/src/features/Tutorial/config/playTutorial/rollupModelSteps.ts @@ -90,7 +90,7 @@ export const rollupModelSteps: TutorialStep[] = [ wizardStep: 0, }, { - element: '[data-tutorial-id="materialized-select"]', + element: '[data-tutorial-id="materialization-select"]', popover: { title: 'Materialization', description: diff --git a/web/src/features/Tutorial/config/playTutorial/selectModelSteps.ts b/web/src/features/Tutorial/config/playTutorial/selectModelSteps.ts index c127a53..ba81edd 100644 --- a/web/src/features/Tutorial/config/playTutorial/selectModelSteps.ts +++ b/web/src/features/Tutorial/config/playTutorial/selectModelSteps.ts @@ -87,7 +87,7 @@ export const selectModelSteps: TutorialStep[] = [ wizardStep: 0, }, { - element: '[data-tutorial-id="materialized-select"]', + element: '[data-tutorial-id="materialization-select"]', popover: { title: 'Materialization', description: diff --git a/web/src/features/Tutorial/config/playTutorial/unionModelSteps.ts b/web/src/features/Tutorial/config/playTutorial/unionModelSteps.ts index 439d311..661d569 100644 --- a/web/src/features/Tutorial/config/playTutorial/unionModelSteps.ts +++ b/web/src/features/Tutorial/config/playTutorial/unionModelSteps.ts @@ -90,7 +90,7 @@ export const unionModelSteps: TutorialStep[] = [ wizardStep: 0, }, { - element: '[data-tutorial-id="materialized-select"]', + element: '[data-tutorial-id="materialization-select"]', popover: { title: 'Materialization', description: diff --git a/web/src/features/Tutorial/data/joinModelDemo.ts b/web/src/features/Tutorial/data/joinModelDemo.ts index 4cd5822..a89ad30 100644 --- a/web/src/features/Tutorial/data/joinModelDemo.ts +++ b/web/src/features/Tutorial/data/joinModelDemo.ts @@ -11,7 +11,7 @@ export const joinModelDemoData: DemoData = { type: 'int_join_models', group: 'sales', topic: 'orders', - materialized: 'incremental' as const, + materialization: 'incremental' as const, // Data Modeling - from with join from: { diff --git a/web/src/features/Tutorial/data/lookbackModelDemo.ts b/web/src/features/Tutorial/data/lookbackModelDemo.ts index d093042..5725064 100644 --- a/web/src/features/Tutorial/data/lookbackModelDemo.ts +++ b/web/src/features/Tutorial/data/lookbackModelDemo.ts @@ -11,7 +11,7 @@ export const lookbackModelDemoData: DemoData = { type: 'int_lookback_model', group: 'sales', topic: 'orders', - materialized: 'incremental', + materialization: 'incremental', // Data Modeling fromModel: 'stg__sales__orders__standardized', diff --git a/web/src/features/Tutorial/data/rollupModelDemo.ts b/web/src/features/Tutorial/data/rollupModelDemo.ts index a6d76a6..27ddc4b 100644 --- a/web/src/features/Tutorial/data/rollupModelDemo.ts +++ b/web/src/features/Tutorial/data/rollupModelDemo.ts @@ -11,7 +11,7 @@ export const rollupModelDemoData: DemoData = { type: 'int_rollup_model', group: 'sales', topic: 'revenue', - materialized: 'incremental', + materialization: 'incremental', // Data Modeling from: { diff --git a/web/src/features/Tutorial/data/selectModelDemo.ts b/web/src/features/Tutorial/data/selectModelDemo.ts index 4f5fe96..e01e176 100644 --- a/web/src/features/Tutorial/data/selectModelDemo.ts +++ b/web/src/features/Tutorial/data/selectModelDemo.ts @@ -11,7 +11,7 @@ export const selectModelDemoData: DemoData = { type: 'int_select_model', group: 'customers', topic: 'profiles', - materialized: 'incremental', + materialization: 'incremental', // Data Modeling - from from: { diff --git a/web/src/features/Tutorial/data/unionModelDemo.ts b/web/src/features/Tutorial/data/unionModelDemo.ts index 00156ea..0a9c3f3 100644 --- a/web/src/features/Tutorial/data/unionModelDemo.ts +++ b/web/src/features/Tutorial/data/unionModelDemo.ts @@ -11,7 +11,7 @@ export const unionModelDemoData: DemoData = { type: 'int_union_models', group: 'sales', topic: 'items', - materialized: 'incremental', + materialization: 'incremental', from: { model: 'stg__sales__items__order_details', diff --git a/web/src/features/Tutorial/hooks/useAssistTutorial.ts b/web/src/features/Tutorial/hooks/useAssistTutorial.ts index c854c03..7c49030 100644 --- a/web/src/features/Tutorial/hooks/useAssistTutorial.ts +++ b/web/src/features/Tutorial/hooks/useAssistTutorial.ts @@ -82,7 +82,7 @@ export function useAssistTutorial({ modelState.source, modelState.type, modelState.group, - modelState.materialized, + modelState.materialization, modelState.fromModel, modelState.fromSource, modelState.hasJoins, diff --git a/web/src/features/Tutorial/hooks/usePlayTutorial.ts b/web/src/features/Tutorial/hooks/usePlayTutorial.ts index 3a171ff..cdedf1d 100644 --- a/web/src/features/Tutorial/hooks/usePlayTutorial.ts +++ b/web/src/features/Tutorial/hooks/usePlayTutorial.ts @@ -208,9 +208,9 @@ export function usePlayTutorial({ } else if (element.includes('topic-input')) { // Prefill topic onDataPrefill({ topic: demoData.topic }); - } else if (element.includes('materialized-select')) { + } else if (element.includes('materialization-select')) { // Prefill materialization - onDataPrefill({ materialized: demoData.materialized }); + onDataPrefill({ materialization: demoData.materialization }); } else if (element.includes('select-node')) { // Prefill source selection (from.model or from.source) if (demoData.from) { diff --git a/web/src/forms/FieldSelectSingle.tsx b/web/src/forms/FieldSelectSingle.tsx index bd4325b..cf26138 100644 --- a/web/src/forms/FieldSelectSingle.tsx +++ b/web/src/forms/FieldSelectSingle.tsx @@ -7,6 +7,7 @@ export type FieldSelectSingleProps = ControllerRenderProps & { label?: string; options: { label: string; value: string }[]; tooltipText?: string; + placeholder?: string; className?: string; inputClassName?: string; labelClass?: string; diff --git a/web/src/pages/ModelCreate.tsx b/web/src/pages/ModelCreate.tsx index 8887eb4..afa4750 100644 --- a/web/src/pages/ModelCreate.tsx +++ b/web/src/pages/ModelCreate.tsx @@ -1,6 +1,11 @@ import { InformationCircleIcon } from '@heroicons/react/20/solid'; import type { Api } from '@shared/api/types'; import type { DbtProject } from '@shared/dbt/types'; +import { + getIncrementalStrategy, + getMaterializationType, + getPartitions, +} from '@shared/framework/materialization'; import type { ModelCreateResponse, ModelCreateValidateResponse, @@ -87,6 +92,7 @@ export function ModelCreate({ mode = 'create' }: ModelCreateProps) { showAddColumnModal, editingColumn, isActionActive, + materializationExtras, } = useModelStore(); // Simple local state @@ -170,9 +176,9 @@ export function ModelCreate({ mode = 'create' }: ModelCreateProps) { setBasicField('topic', data.topic); setValue('topic', data.topic); } - if (data.materialized !== undefined) { - setBasicField('materialized', data.materialized); - setValue('materialized', data.materialized as any); + if (data.materialization !== undefined) { + setBasicField('materialization', data.materialization); + setValue('materialization', data.materialization as any); } // Modeling state fields @@ -272,7 +278,7 @@ export function ModelCreate({ mode = 'create' }: ModelCreateProps) { setValue('type', undefined as any); setValue('group', ''); setValue('topic', ''); - setValue('materialized', undefined); + setValue('materialization', undefined); }, [isEditMode, resetStore, setValue, projects]); // Play Tutorial hook - demo walkthrough with prefilled data @@ -298,7 +304,7 @@ export function ModelCreate({ mode = 'create' }: ModelCreateProps) { type: basicFields.type, group: basicFields.group, topic: basicFields.topic, - materialized: basicFields.materialized, + materialization: basicFields.materialization, fromModel, fromSource, hasJoins: @@ -383,7 +389,7 @@ export function ModelCreate({ mode = 'create' }: ModelCreateProps) { const groupOptions = generateGroupOptions(project); const sourceOptions = generateSourceOptions(); const typeOptions = generateTypeOptions(source); - const materializedOptions = generateMaterializedOptions(); + const materializationOptions = generateMaterializedOptions(); const getFormType = useCallback(async () => { if (mode === 'edit') { @@ -510,8 +516,22 @@ export function ModelCreate({ mode = 'create' }: ModelCreateProps) { if (dataToLoad.topic) setValue('topic', dataToLoad.topic); if (dataToLoad.type) setValue('type', dataToLoad.type); if (dataToLoad.source) setValue('source', dataToLoad.source); - if (dataToLoad.materialized) - setValue('materialized', dataToLoad.materialized); + const materializationType = getMaterializationType( + dataToLoad as Parameters[0], + ); + if (materializationType) { + setValue('materialization', materializationType); + } + const loadedStrategy = getIncrementalStrategy( + dataToLoad as Parameters[0], + ); + setValue('incremental_strategy', loadedStrategy); + const loadedPartitions = getPartitions( + dataToLoad as Parameters[0], + ); + if (loadedPartitions) { + setValue('partitioned_by', loadedPartitions); + } if (dataToLoad.projectName) { setValue('projectName', dataToLoad.projectName); } else if (_projects.length > 0) { @@ -523,11 +543,7 @@ export function ModelCreate({ mode = 'create' }: ModelCreateProps) { if (dataToLoad.description) setValue('description', dataToLoad.description); if (dataToLoad.tags) setValue('tags', dataToLoad.tags); - if (dataToLoad.incremental_strategy) - setValue('incremental_strategy', dataToLoad.incremental_strategy); if (dataToLoad.sql_hooks) setValue('sql_hooks', dataToLoad.sql_hooks); - if (dataToLoad.partitioned_by) - setValue('partitioned_by', dataToLoad.partitioned_by); if (dataToLoad.exclude_daily_filter !== undefined) setValue('exclude_daily_filter', dataToLoad.exclude_daily_filter); if (dataToLoad.exclude_date_filter !== undefined) @@ -738,7 +754,10 @@ export function ModelCreate({ mode = 'create' }: ModelCreateProps) { try { if (isEditMode) { // Edit mode: Call framework-model-update - const transformedFormValues = transformFormValuesToApi(apiModel); + const transformedFormValues = transformFormValuesToApi(apiModel, { + clearDeprecatedTopLevelFields: true, + materializationExtras, + }); if (!originalModelPath) { throw new Error('No original model path available for update'); @@ -755,7 +774,9 @@ export function ModelCreate({ mode = 'create' }: ModelCreateProps) { }); } else { // Create mode: Call framework-model-create - const transformedValues = transformFormValuesToApi(apiModel); + const transformedValues = transformFormValuesToApi(apiModel, { + materializationExtras, + }); resp = await api.post({ type: 'framework-model-create', @@ -768,7 +789,9 @@ export function ModelCreate({ mode = 'create' }: ModelCreateProps) { await stateSync.clearState(formType); const successMessage = isEditMode - ? (typeof resp === 'string' ? resp : 'Model updated successfully') + ? typeof resp === 'string' + ? resp + : 'Model updated successfully' : typeof resp === 'string' ? resp || 'Model created successfully' : 'valid' in resp && resp.valid @@ -863,7 +886,7 @@ export function ModelCreate({ mode = 'create' }: ModelCreateProps) { groupOptions={groupOptions} sourceOptions={sourceOptions} typeOptions={typeOptions} - materializedOptions={materializedOptions} + materializationOptions={materializationOptions} isLoading={isProjectsLoading} setValue={(name, value) => { setValue(name, value); diff --git a/web/src/stores/__tests__/buildModelJson.test.ts b/web/src/stores/__tests__/buildModelJson.test.ts index c1f73d8..716c436 100644 --- a/web/src/stores/__tests__/buildModelJson.test.ts +++ b/web/src/stores/__tests__/buildModelJson.test.ts @@ -1,4 +1,8 @@ import { beforeEach, describe, expect, jest, test } from '@jest/globals'; +import { + DEFAULT_INCREMENTAL_PRE_HOOK, + DEFAULT_INCREMENTAL_STRATEGY, +} from '@shared/framework/constants'; jest.mock('../../utils/stateSync', () => ({ stateSync: { @@ -134,6 +138,145 @@ describe('useModelStore round-trip (loadInitialData -> buildModelJson)', () => { }); }); + test('emits materialization instead of deprecated materialized', () => { + useModelStore.getState().loadInitialData({ + name: 'oms_task_stats', + group: 'capeng', + topic: 'swh', + projectName: 'capeng', + type: 'int_select_model', + materialization: 'ephemeral', + from: { model: 'stg__capeng__swh__oms_task_stats' }, + } as never); + + const out = useModelStore.getState().buildModelJson() as Record< + string, + unknown + >; + expect(out.materialization).toBe('ephemeral'); + expect(out).not.toHaveProperty('materialized'); + }); + + test('legacy incremental without a strategy does not gain defaults', () => { + useModelStore.getState().setMode('edit'); + useModelStore.getState().loadInitialData({ + name: 'oms_task_stats', + group: 'capeng', + topic: 'swh', + projectName: 'capeng', + type: 'int_select_model', + materialized: 'incremental', + from: { model: 'stg__capeng__swh__oms_task_stats' }, + } as never); + + const out = useModelStore.getState().buildModelJson() as Record< + string, + unknown + >; + expect(out.materialization).toBe('incremental'); + expect(out).not.toHaveProperty('sql_hooks'); + expect(out).not.toHaveProperty('incremental_strategy'); + }); + + test('omits the generated session pre-hook and keeps an explicit opt-out', () => { + useModelStore.getState().loadInitialData({ + name: 'oms_task_stats', + group: 'capeng', + topic: 'swh', + projectName: 'capeng', + type: 'int_select_model', + materialization: 'incremental', + sql_hooks: { pre: DEFAULT_INCREMENTAL_PRE_HOOK }, + from: { model: 'stg__capeng__swh__oms_task_stats' }, + } as never); + + const withDefault = useModelStore.getState().buildModelJson() as Record< + string, + unknown + >; + expect(withDefault).not.toHaveProperty('sql_hooks'); + + useModelStore.getState().setAdditionalField('sql_hooks', { pre: null }); + const optedOut = useModelStore.getState().buildModelJson() as Record< + string, + unknown + >; + expect(optedOut.sql_hooks).toEqual({ pre: null }); + }); + + test('create mode preselects the default incremental strategy', () => { + useModelStore.getState().setMode('create'); + useModelStore.getState().setBasicField('materialization', 'incremental'); + expect( + useModelStore.getState().additionalFields.incremental_strategy, + ).toEqual({ type: DEFAULT_INCREMENTAL_STRATEGY }); + }); + + test('edit mode does not preselect a strategy when materialization changes', () => { + useModelStore.getState().setMode('edit'); + useModelStore.getState().setBasicField('materialization', 'incremental'); + expect( + useModelStore.getState().additionalFields.incremental_strategy, + ).toBeUndefined(); + expect(useModelStore.getState().additionalFields.sql_hooks).toBeUndefined(); + }); + + test('migrates legacy flat fields into materialization object', () => { + useModelStore.getState().loadInitialData({ + name: 'oms_task_stats', + group: 'capeng', + topic: 'swh', + projectName: 'capeng', + type: 'int_select_model', + materialized: 'incremental', + incremental_strategy: { type: 'delete+insert' }, + partitioned_by: ['portal_partition_daily'], + from: { model: 'stg__capeng__swh__oms_task_stats' }, + } as never); + + const out = useModelStore.getState().buildModelJson() as Record< + string, + unknown + >; + expect(out.materialization).toEqual({ + type: 'incremental', + strategy: { type: 'delete+insert' }, + partitions: ['portal_partition_daily'], + }); + expect(out).not.toHaveProperty('incremental_strategy'); + expect(out).not.toHaveProperty('partitioned_by'); + }); + + test('preserves materialization extras when rebuilding', () => { + useModelStore.getState().loadInitialData({ + name: 'oms_task_stats', + group: 'capeng', + topic: 'swh', + projectName: 'capeng', + type: 'int_select_model', + materialization: { + type: 'incremental', + format: 'iceberg', + strategy: { type: 'append' }, + }, + from: { model: 'stg__capeng__swh__oms_task_stats' }, + } as never); + + useModelStore.getState().setAdditionalField('incremental_strategy', { + type: 'delete+insert', + }); + + const out = useModelStore.getState().buildModelJson() as Record< + string, + unknown + >; + expect(out.materialization).toMatchObject({ + type: 'incremental', + format: 'iceberg', + strategy: { type: 'delete+insert' }, + }); + }); + test('collapses group_by: [{ type: "dims" }] to the "dims" shorthand', () => { // The shorthand collapse is documented in docs/models/README.md. useModelStore.getState().loadInitialData({ diff --git a/web/src/stores/useModelStore.ts b/web/src/stores/useModelStore.ts index f5d1cda..1bd2e04 100644 --- a/web/src/stores/useModelStore.ts +++ b/web/src/stores/useModelStore.ts @@ -1,10 +1,19 @@ import type { DbtProject } from '@shared/dbt/types'; import { + DEFAULT_INCREMENTAL_PRE_HOOK, DEFAULT_INCREMENTAL_STRATEGY, FRAMEWORK_PARTITIONS, GROUP_BY_DIMS, normalizeGroupBy, } from '@shared/framework/constants'; +import { + buildMaterializationForWizardOutput, + getIncrementalStrategy, + getMaterializationType, + getPartitions, + type MaterializationExtras, + pickMaterializationExtras, +} from '@shared/framework/materialization'; import type { FrameworkInterval, FrameworkModel, @@ -13,6 +22,7 @@ import type { import type { SchemaLightdashMetric } from '@shared/schema/types/lightdash.metric.schema'; import type { SchemaModelGroupBy } from '@shared/schema/types/model.group_by.schema'; import type { SchemaModelLightdash } from '@shared/schema/types/model.lightdash.schema'; +import type { SchemaModelMaterialization } from '@shared/schema/types/model.materialization.schema'; import type { SchemaModelMaterialized } from '@shared/schema/types/model.materialized.schema'; import type { IncrementalStrategy, @@ -363,7 +373,7 @@ export type ModelingStateType = { group: string; topic: string; type: FrameworkModel['type'] | ''; - materialized?: SchemaModelMaterialized; + materialization?: SchemaModelMaterialized; projectName: string; source?: string; } & ModelingStateAdapter & { @@ -384,7 +394,7 @@ export interface ModelStore { group: string; topic: string; type: FrameworkModel['type'] | ''; - materialized?: SchemaModelMaterialized; + materialization?: SchemaModelMaterialized; //description?: string; projectName: string; source?: string; @@ -428,6 +438,9 @@ export interface ModelStore { additionalFields: AdditionalFieldsSchema; + /** Nested materialization keys the wizard does not edit (format, bucket, …) */ + materializationExtras: MaterializationExtras; + /** Default incremental strategy from extension settings, fetched via preferences API */ defaultIncrementalStrategy: string | undefined; @@ -599,7 +612,7 @@ const initialBasicFields = { group: '', topic: '', type: '' as FrameworkModel['type'] | '', - materialized: undefined, + materialization: undefined, //description: '', projectName: '', source: '', @@ -678,6 +691,7 @@ export const useModelStore = create()( where: null, dataModeling: initialDataModeling, additionalFields: initialAdditionalFields, + materializationExtras: {}, defaultIncrementalStrategy: undefined, navigationNodeType: null, showColumnConfiguration: false, @@ -873,11 +887,11 @@ export const useModelStore = create()( }, 0); } - // Clear materialized for mart models (they don't support it) - if (newBasicFields.materialized !== undefined) { - newBasicFields.materialized = undefined; + // Clear materialization for mart models (they don't support it) + if (newBasicFields.materialization !== undefined) { + newBasicFields.materialization = undefined; setTimeout(() => { - void get().saveField('materialized', null); + void get().saveField('materialization', null); }, 0); } @@ -900,54 +914,13 @@ export const useModelStore = create()( } } - // Handle materialized changes: manage default pre-hooks and clear incremental fields - if (field === 'materialized') { - const defaultPreHook = - "set session iterative_optimizer_timeout='60m'; set session query_max_planning_time='60m'"; - - if (value === 'incremental') { - // Add default pre-hook if not already present - const currentSqlHooks = state.additionalFields.sql_hooks; - const currentPreHook = currentSqlHooks?.pre; - - let newPreHookValue: string | [string, ...string[]] | undefined; - - if (currentPreHook) { - // Check if default hook already exists - const currentHooksArray = Array.isArray(currentPreHook) - ? currentPreHook - : [currentPreHook]; - - const hasDefaultHook = currentHooksArray.includes(defaultPreHook); - - if (!hasDefaultHook) { - // Add default hook to existing hooks - const updatedHooks = [...currentHooksArray, defaultPreHook]; - newPreHookValue = - updatedHooks.length === 1 - ? updatedHooks[0] - : (updatedHooks as [string, ...string[]]); - } else { - // Default hook already exists, keep current value - newPreHookValue = currentPreHook; - } - } else { - // No existing hooks, set as string (not array) - newPreHookValue = defaultPreHook; - } - - newAdditionalFields = { - ...newAdditionalFields, - sql_hooks: { - ...currentSqlHooks, - pre: newPreHookValue, - }, - }; - setTimeout(() => { - void get().saveField('sql_hooks', newAdditionalFields.sql_hooks); - }, 0); - - // Preselect default incremental strategy from store state (fetched via preferences API) + // Handle materialization changes: manage default pre-hooks and clear incremental fields + if (field === 'materialization') { + // SQL generation applies the default strategy and session pre-hook + // when the JSON omits them. Preselect a strategy only while creating + // a model. The pre-hook stays out of the file until the user edits it; + // `sql_hooks.pre: null` is how they turn the generated hook off. + if (value === 'incremental' && state.mode === 'create') { if (!state.additionalFields.incremental_strategy?.type) { const defaultStrategy = state.defaultIncrementalStrategy ?? @@ -966,47 +939,33 @@ export const useModelStore = create()( ); }, 0); } - } else { - // Remove default pre-hook when changing away from incremental + } else if (value !== 'incremental') { const currentSqlHooks = state.additionalFields.sql_hooks; - if (currentSqlHooks?.pre) { - const currentPreHook = currentSqlHooks.pre; - - // Filter out default pre-hook from current hooks - let filteredHooks: string | [string, ...string[]] | undefined; - if (Array.isArray(currentPreHook)) { - const filteredHooksArray = currentPreHook.filter( - (hook) => hook !== defaultPreHook, - ); - if (filteredHooksArray.length === 0) { - filteredHooks = undefined; - } else { - filteredHooks = filteredHooksArray as [string, ...string[]]; - } - } else if (currentPreHook === defaultPreHook) { - filteredHooks = undefined; - } else { - filteredHooks = [currentPreHook] as [string, ...string[]]; - } - + const currentPreHook = currentSqlHooks?.pre; + if ( + currentPreHook === DEFAULT_INCREMENTAL_PRE_HOOK || + (Array.isArray(currentPreHook) && + currentPreHook.length === 1 && + currentPreHook[0] === DEFAULT_INCREMENTAL_PRE_HOOK) + ) { + const { pre: _pre, ...restHooks } = currentSqlHooks ?? {}; + const nextHooks = + restHooks.post !== undefined ? restHooks : undefined; newAdditionalFields = { ...newAdditionalFields, - sql_hooks: { - ...currentSqlHooks, - pre: filteredHooks, - }, + sql_hooks: nextHooks, }; setTimeout(() => { - void get().saveField( - 'sql_hooks', - newAdditionalFields.sql_hooks, - ); + void get().saveField('sql_hooks', nextHooks ?? null); }, 0); } } - // Clear incremental_strategy and partitioned_by when not 'incremental' + // Clear incremental_strategy, partitioned_by, and extras when not incremental if (value !== 'incremental') { + if (Object.keys(get().materializationExtras).length > 0) { + set({ materializationExtras: {} }); + } if (state.additionalFields.incremental_strategy !== undefined) { newAdditionalFields = { ...newAdditionalFields, @@ -1096,8 +1055,43 @@ export const useModelStore = create()( if (data.group !== undefined) state.setBasicField('group', data.group); if (data.topic !== undefined) state.setBasicField('topic', data.topic); if (data.type !== undefined) state.setBasicField('type', data.type); - if (data.materialized !== undefined) - state.setBasicField('materialized', data.materialized); + const materializationInput = data as { + materialized?: SchemaModelMaterialized; + materialization?: SchemaModelMaterialization; + incremental_strategy?: IncrementalStrategy; + partitioned_by?: SchemaModelPartitionedBy; + }; + + const materializationType = getMaterializationType(materializationInput); + if (materializationType !== undefined) { + // Direct write: setBasicField('materialization') also injects the + // default strategy and session pre-hook, which belong on create, not load. + set((current) => ({ + basicFields: { + ...current.basicFields, + materialization: materializationType, + }, + })); + } + + const strategyFromFile = getIncrementalStrategy(materializationInput); + if (strategyFromFile !== undefined) { + state.setAdditionalField('incremental_strategy', strategyFromFile); + } + + const partitionsFromFile = getPartitions(materializationInput); + if (partitionsFromFile !== undefined) { + state.setAdditionalField('partitioned_by', partitionsFromFile); + } + + const matField = materializationInput.materialization; + if (matField && typeof matField === 'object') { + set({ + materializationExtras: pickMaterializationExtras(matField), + }); + } else { + set({ materializationExtras: {} }); + } if (data.projectName !== undefined) state.setBasicField('projectName', data.projectName); if (data.source !== undefined) state.setBasicField('source', data.source); @@ -1253,10 +1247,7 @@ export const useModelStore = create()( // `materialization: { type: "incremental", ... }` (object form). // Both must be checked to avoid discarding partitioned_by. const isIncremental = - data.materialized === 'incremental' || - (data as any).materialization === 'incremental' || - (typeof (data as any).materialization === 'object' && - (data as any).materialization?.type === 'incremental'); + getMaterializationType(materializationInput) === 'incremental'; if (!isIncremental && key === 'partitioned_by') { value = undefined; } else if (Array.isArray(value)) { @@ -1700,6 +1691,7 @@ export const useModelStore = create()( where: null, dataModeling: initialDataModeling, additionalFields: initialAdditionalFields, + materializationExtras: {}, navigationNodeType: null, showColumnConfiguration: false, editingColumn: null, @@ -1946,7 +1938,18 @@ export const useModelStore = create()( ); Object.assign(fromObject, transformationConfigs); - const additionalFields = buildAdditionalFields(state.additionalFields); + const { + incremental_strategy: _incrementalStrategy, + partitioned_by: _partitionedBy, + ...additionalFieldsWithoutMaterialization + } = omitGeneratedPreHook(buildAdditionalFields(state.additionalFields)); + + const materialization = buildMaterializationForWizardOutput({ + type: basicFields.materialization, + strategy: state.additionalFields.incremental_strategy, + partitions: state.additionalFields.partitioned_by, + extras: state.materializationExtras, + }); // Build the base model JSON const modelJson: Record = { @@ -1954,15 +1957,13 @@ export const useModelStore = create()( group: basicFields.group, topic: basicFields.topic, type: basicFields.type, - ...(basicFields.materialized && { - materialized: basicFields.materialized, - }), + ...(materialization && { materialization }), from: fromObject, select: buildSelectConfig(basicFields, modelingState), group_by: convertGroupByToSchemaModelGroupBy(groupBy), where: where || null, lightdash: null, - ...additionalFields, + ...additionalFieldsWithoutMaterialization, }; // Add CTEs if defined. Strip UI-only keys + drop empty `select` / @@ -1996,19 +1997,6 @@ export const useModelStore = create()( modelJson.lightdash = lightdashConfig; } - // Only coerce to null when the UI explicitly has the field but it's - // empty/falsy. When absent (undefined), leave it out so the backend - // merge preserves the original value from the file. - if (modelJson.partitioned_by !== undefined) { - if ( - !modelJson.partitioned_by || - (Array.isArray(modelJson.partitioned_by) && - modelJson.partitioned_by.length === 0) - ) { - modelJson.partitioned_by = null; - } - } - return modelJson; }, })), @@ -2086,6 +2074,32 @@ export function convertSchemaModelGroupByToModelStoreGroupBy( return groupByItems; } +function omitGeneratedPreHook( + fields: Record, +): Record { + const hooks = fields.sql_hooks as + | { pre?: string | string[] | null; post?: unknown } + | undefined; + if (!hooks) { + return fields; + } + const pre = hooks.pre; + const isDefault = + pre === DEFAULT_INCREMENTAL_PRE_HOOK || + (Array.isArray(pre) && + pre.length === 1 && + pre[0] === DEFAULT_INCREMENTAL_PRE_HOOK); + if (!isDefault) { + return fields; + } + const { pre: _pre, ...rest } = hooks; + if (rest.post === undefined) { + const { sql_hooks: _hooks, ...withoutHooks } = fields; + return withoutHooks; + } + return { ...fields, sql_hooks: rest }; +} + // Exclude `undefined` entries so the backend merge preserves original values // for fields the UI never loaded. Only explicit values (including `null` via // empty-string/false conversion) are sent; `null` tells the backend to delete. diff --git a/web/src/utils/formValidation.ts b/web/src/utils/formValidation.ts index 1657a07..a75cd24 100644 --- a/web/src/utils/formValidation.ts +++ b/web/src/utils/formValidation.ts @@ -41,7 +41,7 @@ export const modelValidationRules = { message: VALIDATION_MESSAGES.maxLength('Topic'), }, }, - materialized: { + materialization: { required: false, // Now optional - validation handled conditionally in validateStep }, }; @@ -55,7 +55,7 @@ export const STEP_VALIDATIONS = { { name: 'type', label: 'Type' }, { name: 'group', label: 'Group' }, { name: 'topic', label: 'Topic' }, - { name: 'materialized', label: 'Materialization' }, + { name: 'materialization', label: 'Materialization' }, ], }, 2: { diff --git a/web/src/utils/wizardHelpers.ts b/web/src/utils/wizardHelpers.ts index 6d3df69..b966615 100644 --- a/web/src/utils/wizardHelpers.ts +++ b/web/src/utils/wizardHelpers.ts @@ -1,3 +1,13 @@ +import { + DEPRECATED_MATERIALIZATION_TOP_LEVEL_KEYS, + deprecatedMaterializationNullSentinels, + normalizeMaterializationFromLegacyRequest, +} from '@shared/framework/materialization'; +import type { SchemaModelMaterialization } from '@shared/schema/types/model.materialization.schema'; +import type { IncrementalStrategy } from '@shared/schema/types/model.materialization.schema'; +import type { SchemaModelMaterialized } from '@shared/schema/types/model.materialized.schema'; +import type { SchemaModelPartitionedBy } from '@shared/schema/types/model.partitioned_by.schema'; + // Check if form has any data to determine discard button state export const checkFormHasData = (values: Record): boolean => { return Object.values(values).some( @@ -49,31 +59,43 @@ export const getPreviousStep = (currentStep: number): number => { return Math.max(currentStep - 1, 0); }; +type TransformOptions = { + /** When true, emit null sentinels so edit merge deletes legacy top-level keys */ + clearDeprecatedTopLevelFields?: boolean; + materializationExtras?: Record; +}; + /** * Transform form values to API format. * Removes UI-only fields like source, originalModelPath, projectName. * Converts select to array if it's not already. - * Adds materialized if it's provided. - * - * @param values - Form values - * @returns API request object + * Builds canonical `materialization` from wizard fields. */ -export const transformFormValuesToApi = (values: Record) => { +export const transformFormValuesToApi = ( + values: Record, + options: TransformOptions = {}, +) => { const { source: _source, - materialized, + materialization, + materialized: legacyMaterialized, projectName, type, originalModelPath: _originalModelPath, + incremental_strategy, + partitioned_by, ...rest } = values; - // Create the API request object excluding UI-only fields + for (const key of DEPRECATED_MATERIALIZATION_TOP_LEVEL_KEYS) { + delete rest[key]; + } + const selectValue = values.select; const apiRequest: Record = { ...rest, type, - projectName, // Include projectName in API request + projectName, }; if (type !== 'int_rollup_model') { @@ -81,13 +103,21 @@ export const transformFormValuesToApi = (values: Record) => { Array.isArray(selectValue) && selectValue.length > 0 ? selectValue : []; } - // Add materialized only if it's provided and not empty - if ( - materialized && - typeof materialized === 'string' && - materialized.trim() !== '' - ) { - apiRequest.materialized = materialized; + const built = normalizeMaterializationFromLegacyRequest({ + materialized: legacyMaterialized as SchemaModelMaterialized | undefined, + materialization: materialization as SchemaModelMaterialization | undefined, + incremental_strategy: incremental_strategy as + | IncrementalStrategy + | undefined, + partitioned_by: partitioned_by as SchemaModelPartitionedBy | undefined, + extras: options.materializationExtras ?? {}, + }); + + if (built) { + apiRequest.materialization = built; + if (options.clearDeprecatedTopLevelFields) { + Object.assign(apiRequest, deprecatedMaterializationNullSentinels()); + } } return apiRequest;