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.
- dda_sdk/__init__.py +44 -0
- dda_sdk/_assets/CLAUDE.md +28 -0
- dda_sdk/_assets/docs/assets/annual_sales_dashboard_example.png +0 -0
- dda_sdk/_assets/docs/assets/favicon.png +0 -0
- dda_sdk/_assets/docs/assets/logo.svg +14 -0
- dda_sdk/_assets/docs/data-freshness.md +5 -0
- dda_sdk/_assets/docs/getting-started.md +36 -0
- dda_sdk/_assets/docs/index.md +27 -0
- dda_sdk/_assets/docs/portal-support.md +55 -0
- dda_sdk/_assets/docs/querying-data.md +85 -0
- dda_sdk/_assets/docs/schema-reference.md +376 -0
- dda_sdk/_assets/docs/stylesheets/extra.css +78 -0
- dda_sdk/_assets/docs/updating.md +29 -0
- dda_sdk/_assets/docs/use-with-claude.md +33 -0
- dda_sdk/_assets/settings.json +14 -0
- dda_sdk/_assets/skills/dda-analytics/SKILL.md +523 -0
- dda_sdk/_assets/skills/indiebi-design-system/README.md +187 -0
- dda_sdk/_assets/skills/indiebi-design-system/SKILL.md +60 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/avatar/avatar-color.png +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/avatar/avatar-dark.png +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/avatar/avatar-white.png +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/favicon/favicon-32.png +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/favicon/favicon-512.png +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/icon/bi-dark-color.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/icon/bi-dark.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/icon/bi-white-color.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/icon/bi-white.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-color-round.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-color.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-dark-color-round.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-dark-color.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-dark-round.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-dark.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-default-round.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-default.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-white-round.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/icon/icon-white.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/logo/logo-dark-on-white.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/logo/logo-dark.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/logo/logo-one-color.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/logo/logo-primary.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/logo/logo-white-color.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/logo/logo-white.svg +1 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/apple.svg +3 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/epic.svg +5 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/gog.svg +5 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/google.svg +7 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/humble.svg +3 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/meta.svg +3 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/microsoft.svg +17 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/nintendo.svg +3 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/playstation.svg +3 -0
- dda_sdk/_assets/skills/indiebi-design-system/assets/platforms/steam.svg +5 -0
- dda_sdk/_assets/skills/indiebi-design-system/colors_and_type.css +338 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-Black.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-BlackItalic.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-Bold.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-BoldItalic.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-ExtraBold.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-ExtraBoldItalic.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-ExtraLight.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-ExtraLightItalic.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-Italic.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-Light.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-LightItalic.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-Medium.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-MediumItalic.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-Regular.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-SemiBold.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-SemiBoldItalic.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Mulish-VariableFont_wght.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-Black.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-BlackItalic.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-Bold.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-BoldItalic.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-Italic.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-Light.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-LightItalic.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-Medium.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-MediumItalic.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-Regular.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-Thin.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/fonts/Roboto-ThinItalic.ttf +0 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/_card.css +41 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/_shell.html +4 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/brand-app-icons.html +36 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/brand-avatar-favicon.html +59 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/brand-logo-construction.html +98 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/brand-logo.html +49 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/brand-pixel-motif.html +101 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/brand-platforms.html +33 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/colors-core.html +17 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/colors-inks.html +51 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/colors-secondary.html +15 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/colors-sequential.html +45 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/colors-theme-dark.html +18 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/component-buttons.html +40 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/component-chart-line.html +49 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/component-checkbox.html +110 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/component-forms.html +37 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/component-kpi.html +26 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/component-nav.html +53 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/component-table.html +29 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/spacing-elevation.html +19 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/spacing-radii.html +17 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/spacing-scale.html +24 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/type-body.html +28 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/type-display.html +29 -0
- dda_sdk/_assets/skills/indiebi-design-system/preview/type-scale.html +23 -0
- dda_sdk/_assets/skills/indiebi-design-system/ui_kits/data-platform/overview.html +838 -0
- dda_sdk/_assets/skills/indiebi-design-system/ui_kits/diagrams/regional-pricing.html +273 -0
- dda_sdk/_assets/skills/indiebi-design-system/ui_kits/marketing-site/home.html +578 -0
- dda_sdk/_assets/skills/indiebi-design-system/ui_kits/reports/altworks-march-2026.html +301 -0
- dda_sdk/config.py +13 -0
- dda_sdk/docs.py +6 -0
- dda_sdk/duckdb_connector.py +123 -0
- dda_sdk/polars_connector.py +120 -0
- dda_sdk/schemas/__init__.py +52 -0
- dda_sdk/schemas/_fields.py +397 -0
- dda_sdk/schemas/baseline.py +55 -0
- dda_sdk/schemas/countries.py +20 -0
- dda_sdk/schemas/currencies.py +16 -0
- dda_sdk/schemas/engagements_per_sku.py +53 -0
- dda_sdk/schemas/events.py +37 -0
- dda_sdk/schemas/organizations.py +14 -0
- dda_sdk/schemas/portals.py +26 -0
- dda_sdk/schemas/products.py +22 -0
- dda_sdk/schemas/sales.py +47 -0
- dda_sdk/schemas/sales_per_sku.py +55 -0
- dda_sdk/schemas/skus.py +33 -0
- dda_sdk/schemas/visibility.py +37 -0
- dda_sdk/schemas/visibility_wishlist_per_sku.py +43 -0
- dda_sdk/schemas/wishlist_actions.py +31 -0
- dda_sdk/schemas/wishlist_cohorts.py +29 -0
- dda_sdk/ui.py +10 -0
- dda_sdk/updater.py +20 -0
- dda_sdk/versioning.py +72 -0
- dda_sdk/workspace_sync.py +61 -0
- dda_sdk-0.0.1.dist-info/METADATA +11 -0
- dda_sdk-0.0.1.dist-info/RECORD +142 -0
- dda_sdk-0.0.1.dist-info/WHEEL +4 -0
- 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
|
|
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.
|