dda-sdk 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. dda_sdk/__init__.py +44 -0
  2. dda_sdk/_assets/CLAUDE.md +28 -0
  3. dda_sdk/_assets/docs/assets/annual_sales_dashboard_example.png +0 -0
  4. dda_sdk/_assets/docs/assets/favicon.png +0 -0
  5. dda_sdk/_assets/docs/assets/logo.svg +14 -0
  6. dda_sdk/_assets/docs/data-freshness.md +5 -0
  7. dda_sdk/_assets/docs/getting-started.md +36 -0
  8. dda_sdk/_assets/docs/index.md +27 -0
  9. dda_sdk/_assets/docs/portal-support.md +55 -0
  10. dda_sdk/_assets/docs/querying-data.md +85 -0
  11. dda_sdk/_assets/docs/schema-reference.md +376 -0
  12. dda_sdk/_assets/docs/stylesheets/extra.css +78 -0
  13. dda_sdk/_assets/docs/updating.md +29 -0
  14. dda_sdk/_assets/docs/use-with-claude.md +33 -0
  15. dda_sdk/_assets/settings.json +14 -0
  16. dda_sdk/_assets/skills/dda-analytics/SKILL.md +523 -0
  17. dda_sdk/_assets/skills/indiebi-design-system/README.md +187 -0
  18. dda_sdk/_assets/skills/indiebi-design-system/SKILL.md +60 -0
  19. dda_sdk/_assets/skills/indiebi-design-system/assets/avatar/avatar-color.png +0 -0
  20. dda_sdk/_assets/skills/indiebi-design-system/assets/avatar/avatar-dark.png +0 -0
  21. dda_sdk/_assets/skills/indiebi-design-system/assets/avatar/avatar-white.png +0 -0
  22. dda_sdk/_assets/skills/indiebi-design-system/assets/favicon/favicon-32.png +0 -0
  23. dda_sdk/_assets/skills/indiebi-design-system/assets/favicon/favicon-512.png +0 -0
  24. dda_sdk/_assets/skills/indiebi-design-system/assets/icon/bi-dark-color.svg +1 -0
  25. dda_sdk/_assets/skills/indiebi-design-system/assets/icon/bi-dark.svg +1 -0
  26. dda_sdk/_assets/skills/indiebi-design-system/assets/icon/bi-white-color.svg +1 -0
  27. dda_sdk/_assets/skills/indiebi-design-system/assets/icon/bi-white.svg +1 -0
  28. dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-color-round.svg +1 -0
  29. dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-color.svg +1 -0
  30. dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-dark-color-round.svg +1 -0
  31. dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-dark-color.svg +1 -0
  32. dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-dark-round.svg +1 -0
  33. dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-dark.svg +1 -0
  34. dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-default-round.svg +1 -0
  35. dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-default.svg +1 -0
  36. dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-white-round.svg +1 -0
  37. dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-white.svg +1 -0
  38. dda_sdk/_assets/skills/indiebi-design-system/assets/logo/logo-dark-on-white.svg +1 -0
  39. dda_sdk/_assets/skills/indiebi-design-system/assets/logo/logo-dark.svg +1 -0
  40. dda_sdk/_assets/skills/indiebi-design-system/assets/logo/logo-one-color.svg +1 -0
  41. dda_sdk/_assets/skills/indiebi-design-system/assets/logo/logo-primary.svg +1 -0
  42. dda_sdk/_assets/skills/indiebi-design-system/assets/logo/logo-white-color.svg +1 -0
  43. dda_sdk/_assets/skills/indiebi-design-system/assets/logo/logo-white.svg +1 -0
  44. dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/apple.svg +3 -0
  45. dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/epic.svg +5 -0
  46. dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/gog.svg +5 -0
  47. dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/google.svg +7 -0
  48. dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/humble.svg +3 -0
  49. dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/meta.svg +3 -0
  50. dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/microsoft.svg +17 -0
  51. dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/nintendo.svg +3 -0
  52. dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/playstation.svg +3 -0
  53. dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/steam.svg +5 -0
  54. dda_sdk/_assets/skills/indiebi-design-system/colors_and_type.css +338 -0
  55. dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-Black.ttf +0 -0
  56. dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-BlackItalic.ttf +0 -0
  57. dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-Bold.ttf +0 -0
  58. dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-BoldItalic.ttf +0 -0
  59. dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-ExtraBold.ttf +0 -0
  60. dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-ExtraBoldItalic.ttf +0 -0
  61. dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-ExtraLight.ttf +0 -0
  62. dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-ExtraLightItalic.ttf +0 -0
  63. dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-Italic.ttf +0 -0
  64. dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-Light.ttf +0 -0
  65. dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-LightItalic.ttf +0 -0
  66. dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-Medium.ttf +0 -0
  67. dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-MediumItalic.ttf +0 -0
  68. dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-Regular.ttf +0 -0
  69. dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-SemiBold.ttf +0 -0
  70. dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-SemiBoldItalic.ttf +0 -0
  71. dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-VariableFont_wght.ttf +0 -0
  72. dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-Black.ttf +0 -0
  73. dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-BlackItalic.ttf +0 -0
  74. dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-Bold.ttf +0 -0
  75. dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-BoldItalic.ttf +0 -0
  76. dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-Italic.ttf +0 -0
  77. dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-Light.ttf +0 -0
  78. dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-LightItalic.ttf +0 -0
  79. dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-Medium.ttf +0 -0
  80. dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-MediumItalic.ttf +0 -0
  81. dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-Regular.ttf +0 -0
  82. dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-Thin.ttf +0 -0
  83. dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-ThinItalic.ttf +0 -0
  84. dda_sdk/_assets/skills/indiebi-design-system/preview/_card.css +41 -0
  85. dda_sdk/_assets/skills/indiebi-design-system/preview/_shell.html +4 -0
  86. dda_sdk/_assets/skills/indiebi-design-system/preview/brand-app-icons.html +36 -0
  87. dda_sdk/_assets/skills/indiebi-design-system/preview/brand-avatar-favicon.html +59 -0
  88. dda_sdk/_assets/skills/indiebi-design-system/preview/brand-logo-construction.html +98 -0
  89. dda_sdk/_assets/skills/indiebi-design-system/preview/brand-logo.html +49 -0
  90. dda_sdk/_assets/skills/indiebi-design-system/preview/brand-pixel-motif.html +101 -0
  91. dda_sdk/_assets/skills/indiebi-design-system/preview/brand-platforms.html +33 -0
  92. dda_sdk/_assets/skills/indiebi-design-system/preview/colors-core.html +17 -0
  93. dda_sdk/_assets/skills/indiebi-design-system/preview/colors-inks.html +51 -0
  94. dda_sdk/_assets/skills/indiebi-design-system/preview/colors-secondary.html +15 -0
  95. dda_sdk/_assets/skills/indiebi-design-system/preview/colors-sequential.html +45 -0
  96. dda_sdk/_assets/skills/indiebi-design-system/preview/colors-theme-dark.html +18 -0
  97. dda_sdk/_assets/skills/indiebi-design-system/preview/component-buttons.html +40 -0
  98. dda_sdk/_assets/skills/indiebi-design-system/preview/component-chart-line.html +49 -0
  99. dda_sdk/_assets/skills/indiebi-design-system/preview/component-checkbox.html +110 -0
  100. dda_sdk/_assets/skills/indiebi-design-system/preview/component-forms.html +37 -0
  101. dda_sdk/_assets/skills/indiebi-design-system/preview/component-kpi.html +26 -0
  102. dda_sdk/_assets/skills/indiebi-design-system/preview/component-nav.html +53 -0
  103. dda_sdk/_assets/skills/indiebi-design-system/preview/component-table.html +29 -0
  104. dda_sdk/_assets/skills/indiebi-design-system/preview/spacing-elevation.html +19 -0
  105. dda_sdk/_assets/skills/indiebi-design-system/preview/spacing-radii.html +17 -0
  106. dda_sdk/_assets/skills/indiebi-design-system/preview/spacing-scale.html +24 -0
  107. dda_sdk/_assets/skills/indiebi-design-system/preview/type-body.html +28 -0
  108. dda_sdk/_assets/skills/indiebi-design-system/preview/type-display.html +29 -0
  109. dda_sdk/_assets/skills/indiebi-design-system/preview/type-scale.html +23 -0
  110. dda_sdk/_assets/skills/indiebi-design-system/ui_kits/data-platform/overview.html +838 -0
  111. dda_sdk/_assets/skills/indiebi-design-system/ui_kits/diagrams/regional-pricing.html +273 -0
  112. dda_sdk/_assets/skills/indiebi-design-system/ui_kits/marketing-site/home.html +578 -0
  113. dda_sdk/_assets/skills/indiebi-design-system/ui_kits/reports/altworks-march-2026.html +301 -0
  114. dda_sdk/config.py +13 -0
  115. dda_sdk/docs.py +6 -0
  116. dda_sdk/duckdb_connector.py +123 -0
  117. dda_sdk/polars_connector.py +120 -0
  118. dda_sdk/schemas/__init__.py +52 -0
  119. dda_sdk/schemas/_fields.py +397 -0
  120. dda_sdk/schemas/baseline.py +55 -0
  121. dda_sdk/schemas/countries.py +20 -0
  122. dda_sdk/schemas/currencies.py +16 -0
  123. dda_sdk/schemas/engagements_per_sku.py +53 -0
  124. dda_sdk/schemas/events.py +37 -0
  125. dda_sdk/schemas/organizations.py +14 -0
  126. dda_sdk/schemas/portals.py +26 -0
  127. dda_sdk/schemas/products.py +22 -0
  128. dda_sdk/schemas/sales.py +47 -0
  129. dda_sdk/schemas/sales_per_sku.py +55 -0
  130. dda_sdk/schemas/skus.py +33 -0
  131. dda_sdk/schemas/visibility.py +37 -0
  132. dda_sdk/schemas/visibility_wishlist_per_sku.py +43 -0
  133. dda_sdk/schemas/wishlist_actions.py +31 -0
  134. dda_sdk/schemas/wishlist_cohorts.py +29 -0
  135. dda_sdk/ui.py +10 -0
  136. dda_sdk/updater.py +20 -0
  137. dda_sdk/versioning.py +72 -0
  138. dda_sdk/workspace_sync.py +61 -0
  139. dda_sdk-0.0.1.dist-info/METADATA +11 -0
  140. dda_sdk-0.0.1.dist-info/RECORD +142 -0
  141. dda_sdk-0.0.1.dist-info/WHEEL +4 -0
  142. dda_sdk-0.0.1.dist-info/entry_points.txt +6 -0
dda_sdk/__init__.py ADDED
@@ -0,0 +1,44 @@
1
+ from importlib.metadata import version as _package_version
2
+
3
+ from dda_sdk.duckdb_connector import DuckDBClient
4
+ from dda_sdk.polars_connector import PolarsClient
5
+ from dda_sdk.schemas import (
6
+ BaselineSchema,
7
+ CountriesSchema,
8
+ CurrenciesSchema,
9
+ EngagementsPerSkuSchema,
10
+ EventsSchema,
11
+ OrganizationsSchema,
12
+ PortalsSchema,
13
+ ProductsSchema,
14
+ SalesPerSkuSchema,
15
+ SalesSchema,
16
+ SkusSchema,
17
+ VisibilitySchema,
18
+ VisibilityWishlistPerSkuSchema,
19
+ WishlistActionsSchema,
20
+ WishlistCohortsSchema,
21
+ )
22
+
23
+ __version__ = _package_version("dda-sdk")
24
+
25
+ __all__ = [
26
+ "__version__",
27
+ "DuckDBClient",
28
+ "PolarsClient",
29
+ "BaselineSchema",
30
+ "CountriesSchema",
31
+ "CurrenciesSchema",
32
+ "EngagementsPerSkuSchema",
33
+ "EventsSchema",
34
+ "OrganizationsSchema",
35
+ "PortalsSchema",
36
+ "ProductsSchema",
37
+ "SalesSchema",
38
+ "SalesPerSkuSchema",
39
+ "SkusSchema",
40
+ "VisibilitySchema",
41
+ "VisibilityWishlistPerSkuSchema",
42
+ "WishlistActionsSchema",
43
+ "WishlistCohortsSchema",
44
+ ]
@@ -0,0 +1,28 @@
1
+ # IndieBI DDA Workspace
2
+
3
+ > This file is managed by the dda-sdk package and is overwritten on every
4
+ > update. Put your own instructions in `CLAUDE.local.md` instead.
5
+
6
+ ## Data Access (dda_sdk)
7
+
8
+ For connector setup (credentials, `.env`), see `README.md`.
9
+ For fetching data and generating charts, use the `dda-analytics` skill
10
+ (`.claude/skills/dda-analytics/SKILL.md`).
11
+
12
+ ## Design System
13
+
14
+ When doing any UI/design/chart/report work, read
15
+ `.claude/skills/indiebi-design-system/SKILL.md` first.
16
+
17
+ ## Your analyses
18
+
19
+ Create each analysis in its own directory under `projects/`. Updates to the
20
+ SDK never touch `projects/`, `.env`, or `CLAUDE.local.md`.
21
+
22
+ ## Updating
23
+
24
+ At session start you may be told a new dda-sdk version is available. To
25
+ update, run `uv run dda-update` — it upgrades the package and refreshes the
26
+ managed files (`.claude/skills/`, `docs/`, `CLAUDE.md`, `.claude/settings.json`).
27
+ Your own Claude settings and hooks go in `.claude/settings.local.json`, which
28
+ is never overwritten.
Binary file
@@ -0,0 +1,14 @@
1
+ <svg width="66" height="66" viewBox="0 0 66 66" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect width="66" height="66" fill="url(#paint0_linear_1_4657)"/>
3
+ <path d="M37.7238 32.2868C40.1898 30.6785 41.7115 27.6668 41.7115 24.6956C41.7115 19.6569 37.5044 15.8887 31.7785 15.8887H23.4278V21.3172H31.4349C34.126 21.3172 36.1068 23.0699 36.1068 25.5099C36.1068 28.0364 34.1607 29.9624 31.4349 29.9624H23.4278V21.3172H17.9849V50.1287H32.047C37.9433 50.1287 42.5922 45.9216 42.5922 40.5335C42.5922 36.8693 40.7961 33.7508 37.7238 32.2868ZM31.738 44.6829H23.4278V35.079H31.738C34.7179 35.079 36.8691 37.1378 36.8691 39.9098C36.8691 42.7309 34.7324 44.7551 31.738 44.6829Z" fill="white"/>
4
+ <path d="M17.9849 15.8714H12.5391V21.3172H17.9849V15.8714Z" fill="white"/>
5
+ <path d="M52.2422 15.8858H46.7964V50.1287H52.2422V15.8858Z" fill="white"/>
6
+ <defs>
7
+ <linearGradient id="paint0_linear_1_4657" x1="9.66548" y1="56.3345" x2="56.3345" y2="9.66548" gradientUnits="userSpaceOnUse">
8
+ <stop stop-color="#8468FF"/>
9
+ <stop offset="0.29" stop-color="#8677FF"/>
10
+ <stop offset="0.65" stop-color="#8784FF"/>
11
+ <stop offset="1" stop-color="#8F8FFF"/>
12
+ </linearGradient>
13
+ </defs>
14
+ </svg>
@@ -0,0 +1,5 @@
1
+ # Data Freshness
2
+
3
+ Data is scraped once per day. The `portals` table includes a `latest_date` column showing the most recent date for which data has been received for each portal/platform/region combination - use it to check how current your data is before running an analysis.
4
+
5
+ If you need more frequent scrapes, contact your IndieBI consultant.
@@ -0,0 +1,36 @@
1
+ # Getting Started
2
+
3
+ ## Download
4
+
5
+ [Download dda-sdk.zip](https://dda-sdk-f2dee2.gitlab.io/dda-sdk.zip).
6
+
7
+ ## Prerequisites
8
+
9
+ - [Python 3.12+](https://www.python.org/downloads/)
10
+ - [uv](https://docs.astral.sh/uv/getting-started/installation/) (Python package manager)
11
+ - Access credentials from your IndieBI account (user ID and SAS token)
12
+
13
+ ## Setup
14
+
15
+ Install dependencies by running in the project root:
16
+
17
+ ```bash
18
+ uv sync
19
+ ```
20
+
21
+ This installs everything the SDK needs. You only need to do this once (and again after any SDK update).
22
+
23
+ ## Configuration
24
+
25
+ Create a `.env` file in your project root (you can copy existing `.env.example` file and substitute your credentials):
26
+
27
+ ```env
28
+ USER_ID=your-user-id
29
+ SAS_TOKEN=your-sas-token
30
+ ```
31
+
32
+ ## Next steps
33
+
34
+ - [Use with Claude](use-with-claude.md) - prompt Claude to generate charts and analysis from your game data, no code required
35
+ - [Write your own queries](querying-data.md) - connect directly via Python and build custom pipelines
36
+ - [Tables & schema reference](schema-reference.md) - available tables and their column definitions
@@ -0,0 +1,27 @@
1
+ # DDA SDK
2
+
3
+ The DDA (Direct Data Access) SDK gives you direct access to IndieBI's data - sales, engagements, promotions, and more - from a single Python interface.
4
+
5
+ Pull data from Steam, Nintendo, PlayStation, and other platforms without touching raw files or wrangling API tokens.
6
+
7
+ ## Why DDA v2 is a step change
8
+
9
+ DDA v2 is built on the [Delta Lake](https://delta.io/) open table standard - the same format used by Databricks, Metabase, DuckDB, and many other tools your team may already use. That means you're not locked into a proprietary format: your data works wherever Delta tables work.
10
+
11
+ A few things that make this a meaningful upgrade:
12
+
13
+ - **One set of credentials, all your data** - whether you're a studio with a single title or a publisher managing dozens of partners, you access everything through a single connection. No juggling multiple logins or data exports.
14
+ - **Connect the tools you already use** - because the data lives in an open format, you can point Databricks, Metabase, DuckDB UI, or your own notebooks directly at it without any extra wrangling.
15
+ - **Always-fresh data, no interruptions** - in v1, a data refresh could cut off a download mid-flight. That's gone: reads and refreshes now happen independently, so your queries always complete cleanly.
16
+ - **All your platforms, one dataset** - Steam, PlayStation, Nintendo, and more are merged into a single unified table. No more downloading separate exports and stitching them together; cross-platform comparisons and rollups just work.
17
+ - **Fits into your existing workflow** - because it's an SDK, you can embed it in notebooks, scheduled pipelines, or BI tools rather than logging into a portal and clicking export. Your data, on your terms.
18
+
19
+ ## What's inside
20
+
21
+ - **DuckDB connector** - low-latency queries against Delta Lake tables on Azure
22
+ - **Polars connector** - lazy evaluation for large date ranges
23
+ - **Typed schemas** - Pandera-validated DataFrames so you know exactly what columns you're working with
24
+
25
+ ## Quick links
26
+
27
+ - [Getting Started](getting-started.md)
@@ -0,0 +1,55 @@
1
+ # Portal Support
2
+
3
+ The SDK ingests data from the storefronts listed below. What data is available per portal depends on what each storefront exposes through its reporting API - not every portal provides the same metrics.
4
+
5
+ To see the exact portal/platform/region combinations active in your account, query the [`portals`](schema-reference.md#portals) table:
6
+
7
+ ```python
8
+ from dda_sdk import DuckDBClient, PortalsSchema
9
+
10
+ with DuckDBClient() as client:
11
+ portals = client.query(PortalsSchema, "SELECT * FROM portals")
12
+
13
+ print(portals.select(["portal", "platform", "region", "latest_date"]))
14
+ ```
15
+
16
+ ---
17
+
18
+ ## Supported portals
19
+
20
+ | Platform | Data sources |
21
+ |---|---|
22
+ | Steam | Sales, Discounts, Store impressions, Wishlists, Wishlist balance |
23
+ | Nintendo | Sales, Discounts, Wishlists |
24
+ | PlayStation | Sales, GameHub sales, Wishlist actions |
25
+ | Epic Games Store | Sales |
26
+ | Microsoft | Sales |
27
+ | GOG | Sales |
28
+ | Humble | Sales |
29
+ | Meta Quest | Sales |
30
+ | Meta Rift | Sales |
31
+ | Google | Sales |
32
+ | Apple App Store | Sales |
33
+
34
+ ---
35
+
36
+ ## Discount data
37
+
38
+ Promotional event data - discount depth, event name, start/end dates, and performance metrics — is available via the [`events`](schema-reference.md#events) table.
39
+
40
+ | Portal | Method | Accuracy |
41
+ |---|---|---|
42
+ | Steam | Scraped directly | High |
43
+ | Nintendo | Scraped directly | High |
44
+ | Other Portals | Detected from revenue changes | Lower — may miss shallow or short discounts |
45
+
46
+ **Scraped** portals provide exact discount depth and named events (e.g. `"Steam Summer Sale 2026"`). **Detected** portals infer a discount period from drops in revenue, so the timing and depth may be approximate, the event name is created, not reflecting what is set on the backend.
47
+
48
+ Events populate the following columns in `events` table:
49
+
50
+ - `event_name` - human-readable name of the sale (e.g. `"Steam Summer Sale 2026"`)
51
+ - `discount` - discount depth as a 0–1 float (`0.40` = 40% off)
52
+ - `date_from` / `date_to` - event window
53
+ - `click_through_rate`, `conversion_rate`, `sales_uplift_score` - performance metrics (may be null if the portal does not report the underlying traffic data)
54
+
55
+ See [schema reference → events](schema-reference.md#events) for the full column list.
@@ -0,0 +1,85 @@
1
+ # Querying Data
2
+
3
+ ## Interactive UI
4
+
5
+ The quickest way to explore your data is the DuckDB web UI. It connects to your storage, registers all available tables, and opens a local SQL editor in the browser — no Python required beyond the initial launch.
6
+
7
+ ```bash
8
+ uv run duckdb-ui
9
+ ```
10
+
11
+ Opens `http://localhost:4213`. All tables are available immediately as views. Press Enter in the terminal to stop the server.
12
+
13
+ ---
14
+
15
+ The SDK also exposes two clients for querying data programmatically. You can create a python file in `/projects` folder (see `/projects/explore.py` as example).
16
+
17
+ ## DuckDBClient
18
+
19
+ Run SQL against your data and get back a validated Polars DataFrame. The best choice for straightforward queries.
20
+
21
+ ```python
22
+ from dda_sdk import DuckDBClient, SalesPerSkuSchema
23
+
24
+ with DuckDBClient() as client:
25
+ df = client.query(
26
+ SalesPerSkuSchema,
27
+ """
28
+ SELECT *
29
+ FROM sales_per_sku
30
+ WHERE date >= '2026-01-01'
31
+ AND date <= '2026-01-31'
32
+ """,
33
+ )
34
+
35
+ print(df["gross_sales"].sum())
36
+ ```
37
+
38
+ The schema class passed to `query()` validates the result - if a column is missing or has the wrong type, you get an error immediately rather than a silent wrong answer downstream.
39
+
40
+ ## PolarsClient
41
+
42
+ Returns a `LazyFrame` - nothing is fetched until you call `.collect()`. Better for large date ranges or when you want to chain multiple transformations before pulling data.
43
+
44
+ ```python
45
+ from dda_sdk import PolarsClient, SalesPerSkuSchema
46
+ import polars as pl
47
+
48
+ with PolarsClient() as client:
49
+ df = (
50
+ client.scan_table(SalesPerSkuSchema)
51
+ .filter(pl.col("date").is_between(pl.date(2026, 1, 1), pl.date(2026, 3, 31)))
52
+ .filter(pl.col("portal_platform_region").str.starts_with("Steam"))
53
+ .group_by(pl.col("date").dt.truncate("1mo"))
54
+ .agg(pl.col("gross_sales").sum())
55
+ .sort("date")
56
+ .collect()
57
+ )
58
+ ```
59
+
60
+ You can also use SQL with `PolarsClient`:
61
+
62
+ ```python
63
+ with PolarsClient() as client:
64
+ df = client.query(
65
+ "SELECT * FROM sales_per_sku WHERE date >= '2026-01-01'"
66
+ ).collect()
67
+ ```
68
+
69
+ ## Passing credentials explicitly
70
+
71
+ Both clients read `USER_ID` and `SAS_TOKEN` from your `.env` by default. You can also pass them directly via `Config`:
72
+
73
+ ```python
74
+ from dda_sdk.config import Config
75
+
76
+ cfg = Config(user_id="u-xxxxx", sas_token="<your-sas-token>")
77
+
78
+ with DuckDBClient(cfg) as client:
79
+ ...
80
+
81
+ with PolarsClient(cfg) as client:
82
+ ...
83
+ ```
84
+
85
+ This is useful when running against a different storage account or when credentials come from a secret manager rather than a `.env` file.