From 351955b0d8b2fc9d76f00cf8ecf6785b76cea750 Mon Sep 17 00:00:00 2001 From: "Carlos R. Mercado" Date: Wed, 10 Jan 2024 09:22:28 -0500 Subject: [PATCH] fix links in README --- r/shroomDK/README.md | 126 +++++++++++++++++++--------------------- r/shroomDK_0.3.0.tar.gz | Bin 8176 -> 8181 bytes 2 files changed, 61 insertions(+), 65 deletions(-) diff --git a/r/shroomDK/README.md b/r/shroomDK/README.md index 9377c33..c4fd90c 100644 --- a/r/shroomDK/README.md +++ b/r/shroomDK/README.md @@ -1,25 +1,25 @@ -# shroomDK +# shroomDK -ShroomDK is an R package for simplifying access to the Flipside Crypto Compass RPC API. More details available at [docs.flipsidecrypto.com/flipside-api/rest-api](https://docs.flipsidecrypto.com/flipside-api/rest-api). +ShroomDK is an R package for simplifying access to the Flipside Crypto Compass RPC API. More details available at [docs.flipsidecrypto.com/api-sdk-developers](https://docs.flipsidecrypto.com/api-sdk-developers/). ## How to get your own ShroomDK API Key -ShroomDK API Keys were originally NFTs on the Ethereum blockchain. They are now standard API keys available in your [flipsidecrypto user profile](https://flipsidecrypto.xyz/account/api-keys). Every user gets 5,000 query seconds as a free Community tier. Additional query seconds can be purchased via the Builder tier. Enterprises seeking [Snowflake Data Shares](https://docs.flipsidecrypto.com/data-shares/snowflake-data-shares) or scaled pricing can purchase access directly via the [Snowflake Marketplace](https://app.snowflake.com/marketplace/listings/Flipside%20Crypto) or reach out via email to `data-shares@flipsidecrypto.com`. +ShroomDK API Keys were originally NFTs on the Ethereum blockchain. They are now standard API keys available in your [flipsidecrypto user profile](https://flipsidecrypto.xyz/settings/api-keys). Every user gets 500 query seconds as a free Community tier. Additional query seconds can be purchased via the Builder or Pro tier. Enterprises seeking [Snowflake Data Shares](https://data.flipsidecrypto.com/) or scaled pricing can purchase reach out via email to `data-shares@flipsidecrypto.com`. The [Data Studio](https://flipsidecrypto.xyz/) remains free for analysts analyzing data ad-hoc, creating dashboards, and testing queries. It is recommended you test queries in the studio prior to using them to pull data via the API. ## Install from CRAN -Current Version: 0.2.1 +Current Version: 0.3.0 -``` +``` install.packages("shroomDK") library(shroomDK) ``` -## How to Install Latest from Github +## How to Install Latest from Github -``` +``` library(devtools) # install if you haven't already devtools::install_github(repo = 'FlipsideCrypto/sdk', subdir = 'r/shroomDK') library(shroomDK) @@ -31,21 +31,21 @@ Intelligently grab up to 1 Gigabyte of data from a SQL query including automatic ### auto_paginate_query() -Documentation can be viewed within RStudio with ```?auto_paginate_query``` for new packages you may need to restart R to get to the documentation. It is summarized here: +Documentation can be viewed within RStudio with `?auto_paginate_query` for new packages you may need to restart R to get to the documentation. It is summarized here: -| Parameter | Description | -|-----------------|-------------------------| -| query | The SQL query to pass to ShroomDK| -| api_key | Your ShroomDK API key| -| page_size | Default 25,000. May return error if page_size is too large (specifically if data exceeds 30MB or entire query >1GB). Ignored if results fit on 1 page of < 15 Mb of data| -| page_count | How many pages, of page_size rows each, to read. Default NULL calculates the ceiling (# rows in results / page_size). Ignored if results fit on 1 page of < 15 Mb of data| -| data_source | Where data is sourced, including specific computation warehouse. Default `"snowflake-default"`. Non-default data sources may require registration of api_key to allowlist| -| data_provider | Who provides data, Default `"flipside"`. Non-default data providers may require registration of api_key to allowlist| | -| api_url | Default to `https://api-v2.flipsidecrypto.xyz/json-rpc` but upgradeable for user| +| Parameter | Description | +|-----------------------------|------------------------------------------| +| query | The SQL query to pass to ShroomDK | +| api_key | Your ShroomDK API key | +| page_size | Default 25,000. May return error if page_size is too large (specifically if data exceeds 30MB or entire query \>1GB). Ignored if results fit on 1 page of \< 15 Mb of data | +| page_count | How many pages, of page_size rows each, to read. Default NULL calculates the ceiling (\# rows in results / page_size). Ignored if results fit on 1 page of \< 15 Mb of data | +| data_source | Where data is sourced, including specific computation warehouse. Default `"snowflake-default"`. Non-default data sources may require registration of api_key to allowlist | +| data_provider | Who provides data, Default `"flipside"`. Non-default data providers may require registration of api_key to allowlist | +| api_url | Default to `https://api-v2.flipsidecrypto.xyz/json-rpc` but upgradeable for user | Returns a data frame of up to `page_size * page_count` rows, see `?clean_query` for more details on column classes. -``` +``` api_key = readLines("api_key.txt") # always gitignore your API keys! pull_data <- auto_paginate_query(" SELECT * FROM ETHEREUM.CORE.FACT_TRANSACTIONS LIMIT 10001", @@ -58,25 +58,23 @@ page_count = NULL) # NULL automatically calculates required number of pages ### create_query_token() -Uses Flipside ShroomDK to create a Query Token to access Flipside Crypto -data. The query token is kept `ttl` hours and available for no-additional cost reads up to `mam` minutes (i.e., cached to the same exact result). -allowing for pagination and multiple requests before expending more daily request uses. +Uses Flipside ShroomDK to create a Query Token to access Flipside Crypto data. The query token is kept `ttl` hours and available for no-additional cost reads up to `mam` minutes (i.e., cached to the same exact result). allowing for pagination and multiple requests before expending more daily request uses. -Documentation can be viewed within RStudio with ```?create_query_token``` for new packages you may need to restart R to get to the documentation. It is summarized here: +Documentation can be viewed within RStudio with `?create_query_token` for new packages you may need to restart R to get to the documentation. It is summarized here: -| Parameter | Description| -|-----------------|-------------------------| -| query | Flipside Crypto Snowflake SQL compatible query as a string| -| api_key | Flipside Crypto ShroomDK API Key| -| ttl | Time-to-live (in hours) to keep query results available. Default 1 hour| -| mam | Max-age-minutes, lifespan of cache. Set to 0 to always re-execute. Default 10 minutes| -| data_source | Where data is sourced, including specific computation warehouse. Default `"snowflake-default"`. Non-default data sources may require registration of api_key to allowlist| -| data_provider | Who provides data, Default `"flipside"`. Non-default data providers may require registration of api_key to allowlist| -| api_url | Default to https://api-v2.flipsidecrypto.xyz/json-rpc but upgradeable for user| +| Parameter | Description | +|-----------------------------|------------------------------------------| +| query | Flipside Crypto Snowflake SQL compatible query as a string | +| api_key | Flipside Crypto ShroomDK API Key | +| ttl | Time-to-live (in hours) to keep query results available. Default 1 hour | +| mam | Max-age-minutes, lifespan of cache. Set to 0 to always re-execute. Default 10 minutes | +| data_source | Where data is sourced, including specific computation warehouse. Default `"snowflake-default"`. Non-default data sources may require registration of api_key to allowlist | +| data_provider | Who provides data, Default `"flipside"`. Non-default data providers may require registration of api_key to allowlist | +| api_url | Default to but upgradeable for user | -Returns a list of `token` and `cached`. Use `token` in `get_query_from_token()`| +Returns a list of `token` and `cached`. Use `token` in `get_query_from_token()`\| -``` +``` # example api_key = readLines("api_key.txt") # always gitignore your API keys! create_query_token( @@ -90,18 +88,17 @@ mam = 5) Access the status of a query run id from `create_query_token()`. -Documentation can be viewed within RStudio with ```?get_query_status``` for new packages you may need to restart R to get to the documentation. It is summarized here: +Documentation can be viewed within RStudio with `?get_query_status` for new packages you may need to restart R to get to the documentation. It is summarized here: -| Parameter | Description| -|-----------------|-------------------------| -| query_run_id | queryRunId from `create_query_token()`, for token stored as `x`, use `x$result$queryRequest$queryRunId`| -| api_key | Flipside Crypto ShroomDK API Key| -| api_url | Default to `https://api-v2.flipsidecrypto.xyz/json-rpc` but upgradeable for user| +| Parameter | Description | +|-----------------------------|------------------------------------------| +| query_run_id | queryRunId from `create_query_token()`, for token stored as `x`, use `x$result$queryRequest$queryRunId` | +| api_key | Flipside Crypto ShroomDK API Key | +| api_url | Default to `https://api-v2.flipsidecrypto.xyz/json-rpc` but upgradeable for user | Returns request content; for content `x`, use `x$result$queryRun$state` and `x$result$queryRun$errorMessage`. Expect one of `QUERY_STATE_READY`, `QUERY_STATE_RUNNING`, `QUERY_STATE_STREAMING_RESULTS`, `QUERY_STATE_SUCCESS`, `QUERY_STATE_FAILED`, `QUERY_STATE_CANCELED`. - -``` +``` api_key = readLines("api_key.txt") # always gitignore your API keys! query = create_query_token("SELECT * FROM ETHEREUM.CORE.FACT_TRANSACTIONS LIMIT 10000", api_key) get_query_status(query$result$queryRequest$queryRunId, api_key) @@ -109,25 +106,24 @@ get_query_status(query$result$queryRequest$queryRunId, api_key) ### get_query_from_token() -Access results of a Query Token (Run ID). This function is for pagination and multiple requests. -It is best suited for debugging and testing new queries. Consider `auto_paginate_query()` for queries already known to work as expected. +Access results of a Query Token (Run ID). This function is for pagination and multiple requests. It is best suited for debugging and testing new queries. Consider `auto_paginate_query()` for queries already known to work as expected. Note: To reduce payload it returns a list of outputs (separating column names from rows). See `clean_query()` for converting result to a data frame. -Documentation can be viewed within RStudio with ```?get_query_from_token``` for new packages you may need to restart R to get to the documentation. It is summarized here: +Documentation can be viewed within RStudio with `?get_query_from_token` for new packages you may need to restart R to get to the documentation. It is summarized here: -| Parameter | Description| -|---------------------|-------------| -| query_run_id | queryRunId from `create_query_token()`, for token stored as `x`, use `x$result$queryRequest$queryRunId`| -| api_key | Flipside Crypto ShroomDK API Key| -| page_number | Results are cached, max 30MB of data per page| -| page_size | Default 1000. Paginate via page_number. May return error if page_size causes data to exceed 30MB| -| result_format | Default to csv. Options: csv and json| -| api_url | Default to https://api-v2.flipsidecrypto.xyz/json-rpc but upgradeable for user| +| Parameter | Description | +|--------------------------------------------|----------------------------| +| query_run_id | queryRunId from `create_query_token()`, for token stored as `x`, use `x$result$queryRequest$queryRunId` | +| api_key | Flipside Crypto ShroomDK API Key | +| page_number | Results are cached, max 30MB of data per page | +| page_size | Default 1000. Paginate via page_number. May return error if page_size causes data to exceed 30MB | +| result_format | Default to csv. Options: csv and json | +| api_url | Default to but upgradeable for user | Returns a list of jsonrpc, id, and result. Within result are: columnNames, columnTypes, rows, page, sql, format, originalQueryRun, redirectedToQueryRun. Use `clean_query()` to transform this into a data frame. If a query exactly matches another recently run query, the run will be redirected to the results of the earlier query run ID to reduce costs. -``` +``` # example api_key = readLines("api_key.txt") # always gitignore your API keys! query <- create_query_token("SELECT * FROM ETHEREUM.CORE.FACT_TRANSACTIONS LIMIT 1000", api_key) @@ -138,13 +134,13 @@ fact_transactions <- get_query_from_token(query$result$queryRequest$queryRunId, CANCEL a query run id from `create_query_token()`. As the new API uses warehouse-seconds to charge users above the free tier, the ability to cancel is critical for cost management. -Documentation can be viewed within RStudio with ```?cancel_query``` for new packages you may need to restart R to get to the documentation. It is summarized here: +Documentation can be viewed within RStudio with `?cancel_query` for new packages you may need to restart R to get to the documentation. It is summarized here: -| Parameter | Description| -|-----------------|-------------| -| query_run_id | queryRunId from `create_query_token()`, for token stored as `x`, use `x$result$queryRequest$queryRunId`| -| api_key | Flipside Crypto ShroomDK API Key| -| api_url | Default to https://api-v2.flipsidecrypto.xyz/json-rpc but upgradeable for user| +| Parameter | Description | +|-----------------------------------------|-------------------------------| +| query_run_id | queryRunId from `create_query_token()`, for token stored as `x`, use `x$result$queryRequest$queryRunId` | +| api_key | Flipside Crypto ShroomDK API Key | +| api_url | Default to but upgradeable for user | Returns a list of the status_canceled (TRUE or FALSE) and the cancel object (which includes related details) @@ -152,18 +148,18 @@ Returns a list of the status_canceled (TRUE or FALSE) and the cancel object (whi Converts query response to data frame while attempting to coerce classes intelligently. -Documentation can be viewed within RStudio with ```?clean_query``` for new packages you may need to restart R to get to the documentation. It is summarized here: +Documentation can be viewed within RStudio with `?clean_query` for new packages you may need to restart R to get to the documentation. It is summarized here: -| Parameter | Description| -|-----------------|--------------| -| request | The request output from `get_query_from_token()`| -| try_simplify | Because requests can return JSON and may not have the same length across values, they may not be data frame compliant (all columns having the same number of rows). A key example would be TX_JSON in EVM FACT_TRANSACTION tables which include 50+ extra details from transaction logs. But other examples like NULLs in TO_ADDRESS can have similar issues. Default TRUE | +| Parameter | Description | +|---------------------------------------|---------------------------------| +| request | The request output from `get_query_from_token()` | +| try_simplify | Because requests can return JSON and may not have the same length across values, they may not be data frame compliant (all columns having the same number of rows). A key example would be TX_JSON in EVM FACT_TRANSACTION tables which include 50+ extra details from transaction logs. But other examples like NULLs in TO_ADDRESS can have similar issues. Default TRUE | Returns a data frame. If `try_simplify` is FALSE OR if `try_simplify` TRUE fails: the data frame is comprised of lists, where each column must be coerced to a desired class (e.g., with `as.numeric()`). Note: The vast majority (95%+) of queries will return a simple data frame with the classes coerced intelligently (e.g., Block_Number being numeric). But check the warnings and check your column classes, if the class is a list then try_simplify failed (i.e., not all columns have the same number of rows when coerced). -``` +``` #example api_key = readLines("api_key.txt") # always gitignore your API keys! query <- create_query_token("SELECT * FROM ETHEREUM.CORE.FACT_TRANSACTIONS LIMIT 1000", api_key) diff --git a/r/shroomDK_0.3.0.tar.gz b/r/shroomDK_0.3.0.tar.gz index 89b64fa53b8f89a4777359d879f4f8165e3d3e44..9e92a9f14fb8326f1487a2e934b06d0d73e601e0 100644 GIT binary patch delta 4707 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