-
Notifications
You must be signed in to change notification settings - Fork 2
1.7.1 #189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
1.7.1 #189
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
7d70610
adding retry policy and raising exceptions on error
digitalghost-dev 547dbff
initial commit
digitalghost-dev eb9e699
successfully returning dataframe in Dagster
digitalghost-dev b69eaaa
dropping constraints and adding run_query
digitalghost-dev 8979621
updating selected columns
digitalghost-dev 90ab475
adding name mapping for dbt models
digitalghost-dev ecbe298
adding name to dagster asset
digitalghost-dev ecf8ad9
initial commit
digitalghost-dev 519a3cf
adding profile and run instructions
digitalghost-dev dc4387b
adding pricing_data table to dbt
digitalghost-dev ca2fdb5
updating soda checks
digitalghost-dev c6545e3
updating models
digitalghost-dev 1fc64c0
updating test outputs
digitalghost-dev 0bf8339
updating asset names
digitalghost-dev ba6f999
updating soda data check asset
digitalghost-dev b03deb6
adding egg group(s) to pokemon command (#188)
digitalghost-dev e72daa2
updating struct to include egg groups (#188)
digitalghost-dev 3ea8ee2
initial commit - supabase
digitalghost-dev be66e64
updating RDS instructions
digitalghost-dev 03e647b
adding missed step in RDS instructions
digitalghost-dev a8a569b
fixing typo, updating aws credentials description
digitalghost-dev 91c59e2
raising error if any DataFrame from a set is empty
digitalghost-dev 2338167
referencing correct function name in error text
digitalghost-dev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
card_data/pipelines/defs/extract/extract_pricing_data.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| from typing import Optional | ||
|
|
||
| import dagster as dg | ||
| import polars as pl | ||
| import requests | ||
| from pydantic import BaseModel, ValidationError | ||
| from termcolor import colored | ||
|
|
||
|
|
||
| SET_PRODUCT_MATCHING = { | ||
| "sv01": "22873", | ||
| "sv02": "23120", | ||
| } | ||
|
|
||
|
|
||
| class CardPricing(BaseModel): | ||
| product_id: int | ||
| name: str | ||
| card_number: str | ||
| market_price: Optional[float] = None | ||
|
|
||
|
|
||
| def is_card(item: dict) -> bool: | ||
| """Check if item has a 'Number' field in extendedData""" | ||
| return any( | ||
| data_field.get("name") == "Number" | ||
| for data_field in item.get("extendedData", []) | ||
| ) | ||
|
|
||
|
|
||
| def get_card_number(card: dict) -> Optional[str]: | ||
| """Get the card number from extendedData""" | ||
| for data_field in card.get("extendedData", []): | ||
| if data_field.get("name") == "Number": | ||
| return data_field.get("value") | ||
| return None | ||
|
|
||
|
|
||
| def extract_card_name(full_name: str) -> str: | ||
| """Extract clean card name, removing variant information after dash""" | ||
| return full_name.partition("-")[0].strip() if "-" in full_name else full_name | ||
|
|
||
|
|
||
| def pull_product_information(set_number: str) -> pl.DataFrame: | ||
| """Pull product and pricing information for a given set number.""" | ||
|
|
||
| print(colored(" →", "blue"), f"Processing set: {set_number}") | ||
|
|
||
| product_id = SET_PRODUCT_MATCHING[set_number] | ||
|
|
||
| # Fetch product data | ||
| products_url = (f"https://tcgcsv.com/tcgplayer/3/{product_id}/products") | ||
| products_data = requests.get(products_url, timeout=30).json() | ||
|
|
||
| # Fetch pricing data | ||
| prices_url = (f"https://tcgcsv.com/tcgplayer/3/{product_id}/prices") | ||
| prices_data = requests.get(prices_url, timeout=30).json() | ||
|
|
||
| price_dict = { | ||
| price["productId"]: price.get("marketPrice") | ||
| for price in prices_data.get("results", []) | ||
| } | ||
|
|
||
| cards_data = [] | ||
| for card in products_data.get("results", []): | ||
| if not is_card(card): | ||
| continue | ||
|
|
||
| card_info = { | ||
| "product_id": card["productId"], | ||
| "name": extract_card_name(card["name"]), | ||
| "card_number": get_card_number(card), | ||
| "market_price": price_dict.get(card["productId"]), | ||
| } | ||
| cards_data.append(card_info) | ||
|
|
||
| # Pydantic validation | ||
| try: | ||
| validated: list[CardPricing] = [CardPricing(**card) for card in cards_data] | ||
| print( | ||
| colored(" ✓", "green"), | ||
| f"Pydantic validation passed for {len(validated)} cards.", | ||
| ) | ||
| except ValidationError as e: | ||
| print(colored(" ✖", "red"), "Pydantic validation failed.") | ||
| print(e) | ||
| raise | ||
|
|
||
| df_data = [card.model_dump(mode="json") for card in validated] | ||
| return pl.DataFrame(df_data) | ||
|
|
||
|
|
||
| @dg.asset(kinds={"API", "Polars", "Pydantic"}, name="build_pricing_dataframe") | ||
| def build_dataframe() -> pl.DataFrame: | ||
| all_cards = [] | ||
| for set_number in SET_PRODUCT_MATCHING.keys(): | ||
| df = pull_product_information(set_number) | ||
|
|
||
| # Raise error if any DataFrame is empty | ||
| if df is None or df.shape[1] == 0 or df.is_empty(): | ||
| error_msg = f"Empty DataFrame returned for set '{set_number}'. " \ | ||
| f"Cannot proceed with drop+replace operation to avoid data loss." | ||
| print(colored(" ✖", "red"), error_msg) | ||
| raise ValueError(error_msg) | ||
|
|
||
| all_cards.append(df) | ||
|
|
||
| concatenated = pl.concat(all_cards) | ||
| print(concatenated) | ||
| return concatenated | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import dagster as dg | ||
| from dagster import RetryPolicy, Backoff | ||
| from sqlalchemy.exc import OperationalError | ||
| from ..extract.extract_pricing_data import build_dataframe | ||
| from ...utils.secret_retriever import fetch_secret | ||
| from termcolor import colored | ||
|
|
||
|
|
||
| @dg.asset( | ||
| deps=[build_dataframe], | ||
| kinds={"Supabase", "Postgres"}, | ||
| retry_policy=RetryPolicy(max_retries=3, delay=2, backoff=Backoff.EXPONENTIAL), | ||
| ) | ||
| def load_pricing_data() -> None: | ||
| database_url: str = fetch_secret() | ||
| table_name: str = "staging.pricing_data" | ||
|
|
||
| df = build_dataframe() | ||
digitalghost-dev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| try: | ||
| df.write_database( | ||
| table_name=table_name, connection=database_url, if_table_exists="replace" | ||
| ) | ||
| print(colored(" ✓", "green"), f"Data loaded into {table_name}") | ||
| except OperationalError as e: | ||
| print(colored(" ✖", "red"), "Connection error in load_pricing_data():", e) | ||
| raise | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 22 additions & 11 deletions
33
card_data/pipelines/poke_cli_dbt/macros/create_relationships.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,16 +1,27 @@ | ||
| {% macro create_relationships() %} | ||
| ALTER TABLE {{ target.schema }}.series ADD CONSTRAINT pk_series PRIMARY KEY (id); | ||
| ALTER TABLE {{ target.schema }}.sets ADD CONSTRAINT pk_sets PRIMARY KEY (set_id); | ||
| ALTER TABLE {{ target.schema }}.cards ADD CONSTRAINT pk_cards PRIMARY KEY (id); | ||
| {{ print("Dropping existing constraints...") }} | ||
|
|
||
| ALTER TABLE public.sets | ||
| ADD CONSTRAINT fk_sets_series | ||
| FOREIGN KEY (series_id) | ||
| REFERENCES public.series (id); | ||
| -- Drop existing constraints if they exist (in reverse dependency order) | ||
| {% do run_query("ALTER TABLE " ~ target.schema ~ ".cards DROP CONSTRAINT IF EXISTS fk_cards_sets") %} | ||
| {% do run_query("ALTER TABLE " ~ target.schema ~ ".sets DROP CONSTRAINT IF EXISTS fk_sets_series") %} | ||
| {% do run_query("ALTER TABLE " ~ target.schema ~ ".cards DROP CONSTRAINT IF EXISTS pk_cards") %} | ||
| {% do run_query("ALTER TABLE " ~ target.schema ~ ".sets DROP CONSTRAINT IF EXISTS pk_sets") %} | ||
| {% do run_query("ALTER TABLE " ~ target.schema ~ ".series DROP CONSTRAINT IF EXISTS pk_series") %} | ||
|
|
||
| ALTER TABLE public.cards | ||
| ADD CONSTRAINT fk_cards_sets | ||
| FOREIGN KEY (set_id) | ||
| REFERENCES public.sets (set_id); | ||
| {{ print("Adding primary keys...") }} | ||
|
|
||
| -- Add primary keys | ||
| {% do run_query("ALTER TABLE " ~ target.schema ~ ".series ADD CONSTRAINT pk_series PRIMARY KEY (id)") %} | ||
| {% do run_query("ALTER TABLE " ~ target.schema ~ ".sets ADD CONSTRAINT pk_sets PRIMARY KEY (set_id)") %} | ||
| {% do run_query("ALTER TABLE " ~ target.schema ~ ".cards ADD CONSTRAINT pk_cards PRIMARY KEY (id)") %} | ||
|
|
||
| {{ print("Adding foreign keys...") }} | ||
|
|
||
| -- Add foreign keys | ||
| {% do run_query("ALTER TABLE " ~ target.schema ~ ".sets ADD CONSTRAINT fk_sets_series FOREIGN KEY (series_id) REFERENCES " ~ target.schema ~ ".series (id)") %} | ||
| {% do run_query("ALTER TABLE " ~ target.schema ~ ".cards ADD CONSTRAINT fk_cards_sets FOREIGN KEY (set_id) REFERENCES " ~ target.schema ~ ".sets (set_id)") %} | ||
|
|
||
digitalghost-dev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| {{ print("Relationships created successfully") }} | ||
|
|
||
| {% do return('') %} | ||
| {% endmacro %} | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| {{ config( | ||
| materialized='table', | ||
| post_hook="{{ enable_rls() }}" | ||
| ) }} | ||
|
|
||
| SELECT product_id, name, card_number, market_price | ||
| FROM {{ source('staging', 'pricing_data') }} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.