Skip to content

Commit f6d38bb

Browse files
docs: add usage section
1 parent 2e1c51d commit f6d38bb

File tree

13 files changed

+711
-225
lines changed

13 files changed

+711
-225
lines changed

.github/workflows/publish-mkdocs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@ jobs:
2424
path: ~/.cache
2525
restore-keys: |
2626
mkdocs-material-
27-
- run: pip install mkdocs-material
27+
- run: pip install mkdocs-material pymdown-extensions
2828
- run: mkdocs gh-deploy --force

docs/fetchers/merchant-center-api.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ garf <PATH_TO_QUERIES> --source merchant-api \
1919
where:
2020

2121
* `<PATH_TO_QUERIES>` - local or remove files containing queries
22-
* `<OUTPUT_TYPE>` - output supported by [`garf-io` library](../garf_io/README.md).
22+
* `<OUTPUT_TYPE>` - output supported by [`garf-io` library](https://github.com/google/garf/tree/main/libs/garf_io#readme).
2323
* `<SOURCE_PARAMETER=VALUE` - key-value pairs to refine fetching, check [available source parameters](#available-source-parameters).
2424

2525
### Available source parameters

docs/get-started/library.md

Lines changed: 26 additions & 211 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
# Use garf as a library
22

33

4-
## initialize subclass `ApiReportFetcher` to get reports
4+
## Fetch reports
55

6-
> For simplicity we're going to use built-in `FakeApiReportFetcher`.
6+
> For simplicity we're going to use built-in `FakeApiClient` to mimic results from an API.
77
88
```python
9-
from garf_core.fetchers import FakeApiReportFetcher
9+
from garf_core import ApiReportFetcher
10+
from garf_core.api_clients import FakeApiClient
1011

11-
report_fetcher = FakeApiReportFetcher(data=[{'campaign': {'id': 1, 'clicks': 10}}])
12+
api_client = FakeApiClient(results=[{'campaign': {'id': 1, 'clicks': 10}}])
13+
report_fetcher = FakeApiReportFetcher(api_client)
1214

13-
# create query text
14-
query_text = "SELECT campaign.id AS campaign_id FROM campaign"
15+
query_text = "SELECT campaign.id AS campaign_id, clicks FROM campaign"
1516

16-
campaigns = report_fetcher.fetch(query_text)
17+
report = report_fetcher.fetch(query_text)
1718
```
1819

19-
#### Use macros in your queries
20+
### Parametrize fetching
2021

2122
```python
2223
parametrized_query_text = """
@@ -34,225 +35,39 @@ active_campaigns = report_fetcher.fetch(
3435
)
3536
```
3637

37-
#### Define queries
38-
39-
There are three ways how you can define a query:
40-
* in a variable
41-
* in a file
42-
* in a class (useful when you have complex parametrization and validation)
43-
44-
```python
45-
from garf_core.base_query import BaseQuery
46-
from garf_io import reader
47-
48-
49-
# 1. define query as a string an save in a variable
50-
query_string = "SELECT campaign.id FROM campaign"
51-
52-
# 2. define path to a query file and read from it
53-
# path can be local
54-
query_path = "path/to/query.sql"
55-
# or remote
56-
query_path = "gs://PROJECT_ID/path/to/query.sql"
57-
58-
# Instantiate reader
59-
reader_client = reader.FileReader()
60-
# And read from the path
61-
query = reader_client.read(query_path)
62-
63-
# 3. define query as a class
64-
65-
# Native style
66-
class Campaigns(BaseQuery):
67-
query_text = """
68-
SELECT
69-
campaign.id
70-
FROM campaign
71-
WHERE campaign.status = {status}
72-
"""
73-
74-
def __init__(self, status: str = "ENABLED") -> None:
75-
self.status = status
76-
77-
# Dataclass style
78-
from dataclasses import dataclass
79-
80-
@dataclass
81-
class Campaigns(BaseQuery):
82-
query_text = """
83-
SELECT
84-
campaign.id
85-
FROM campaign
86-
WHERE campaign.status = {status}
87-
"""
88-
status: str = "ENABLED"
89-
90-
# Old style
91-
class Campaigns(BaseQuery):
92-
def __init__(self, status: str = "ENABLED"):
93-
self.query_text = f"""
94-
SELECT
95-
campaign.id
96-
FROM campaign
97-
WHERE campaign.status = {status}
98-
"""
99-
100-
active_campaigns = report_fetcher.fetch(Campaigns())
101-
inactive_campaigns = report_fetcher.fetch(Campaigns("INACTIVE"))
102-
```
38+
## Work with reports
10339

104-
#### Iteration and slicing
40+
With reports you can perform common operations are iterating over rows of report, slicing, and converting to different structures.
10541

106-
`ApiReportFetcher.fetch` method returns an instance of `GarfReport` object which you can use to perform simple iteration.
10742

10843
```python
109-
query_text = "SELECT campaign.id AS campaign_id, clicks FROM campaign"
110-
campaigns = report_fetcher.fetch(query_text)
44+
# Slicing
45+
report_10_rows = report[0:10]
46+
report_one_column = report['campaign_id']
11147

112-
# iterate over each row of `campaigns` report
113-
for row in campaigns:
114-
# Get element as an attribute
48+
# Iteration
49+
for row in report:
11550
print(row.campaign_id)
11651

117-
# Get element as a slice
118-
print(row["campaign_id"])
119-
120-
# Get element as an index
121-
print(row[0])
122-
123-
# Create new column
124-
row["new_campaign_id"] = row["campaign_id"] + 1
125-
```
126-
127-
128-
You can easily slice the report
129-
130-
```python
131-
# Create new reports by selecting one or more columns
132-
campaign_only_report = campaigns["campaign_id"]
133-
campaign_name_clicks_report = campaigns[["campaign_id", "clicks"]]
134-
135-
# Get subset of the report
136-
# Get first row only
137-
first_campaign_row = campaigns[0]
138-
# Get first ten rows from the report
139-
first_10_rows_from_campaigns = campaigns[0:10]
140-
```
141-
142-
#### Convert report
143-
144-
`GarfReport` can be easily converted to common data structures:
145-
146-
```python
147-
# convert `campaigns` to list of lists
148-
campaigns_list = campaigns.to_list()
149-
150-
# convert `campaigns` to flatten list
151-
campaigns_list = campaigns.to_list(row_type="scalar")
152-
153-
# convert `campaigns` column campaign_id to list
154-
campaigns_list = campaigns["campaign_id"].to_list()
155-
156-
# convert `campaigns` column campaign_id to list with unique values
157-
campaigns_list = campaigns["campaign_id"].to_list(distinct=True)
158-
159-
# convert `campaigns` to list of dictionaries
160-
# each dictionary maps report column to its value, i.e.
161-
# {"campaign_name": "test_campaign", "campaign_id": 1, "clicks": 10}
162-
campaigns_list = campaigns.to_list(row_type="dict")
163-
164-
# convert `campaigns` to pandas DataFrame
165-
campaigns_df = campaigns.to_pandas()
166-
167-
# convert `campaigns` to polars DataFrame
168-
campaigns_df = campaigns.to_polars()
169-
170-
# convert `campaigns` to dictionary
171-
# map campaign_id to campaign_name one-to-one
172-
campaigns_dict = campaigns.to_dict(
173-
key_column="campaign_id",
174-
value_column="clicks",
175-
value_column_output="scalar",
176-
)
177-
178-
# convert `campaigns` to dictionary
179-
# map campaign_id to campaign_name one-to-many
180-
campaigns_dict = campaigns.to_dict(
181-
key_column="campaign_id",
182-
value_column="clicks",
183-
value_column_output="list",
184-
)
52+
# Conversion
53+
df = report.to_pandas()
54+
report_dict = report.to_dict(key_column='campaign_id', value_column='clicks')
18555
```
18656

187-
#### Build report
188-
189-
`GarfReport` can be easily built from pandas or polars data frame:
57+
[:octicons-arrow-right-24: More information](../usage/reports.md)
19058

191-
```
192-
import pandas as pd
193-
import polars as pl
19459

195-
# Pandas
196-
df = pd.DataFrame(data=[[1]], columns=["one"])
197-
report = GarfReport.from_pandas(df)
19860

199-
# Polars
200-
df = pl.DataFrame(data=[[1]], schema=["one"], orient='row')
201-
report = GarfReport.from_polars(df)
202-
```
61+
## Write reports
20362

204-
#### Save report
63+
Reports can be written to various destinations.
20564

206-
`GarfReport` can be easily saved to local or remote storage:
20765

20866
```python
209-
from garf_io import writer
67+
from garf_io.writers import CsvWriter
68+
writer = CsvWriter()
21069

211-
# initialize CSV writer
212-
csv_writer = writer.create_writer('csv', destination_folder="/tmp")
213-
214-
# save report using one of the writers
215-
csv_writer.write(campaigns, destination="my_file_name")
70+
writer.write(report, 'campaigns')
21671
```
21772

218-
Learn more about available writers at [`garf-io` documentation](../libs/garf_io/README.md).
219-
220-
### Combine fetching and saving with `ApiQueryExecutor`
221-
222-
Ensure that `garf-executors` library is installed:
223-
224-
```
225-
pip install garf-executors
226-
```
227-
228-
If your job is to execute query and write it to local/remote storage you can use `ApiQueryExecutor` to do it easily.
229-
> When reading query from file `ApiQueryExecutor` will use query file name as a name for output file/table.
230-
```python
231-
from garf_core.fetchers import FakeApiReportFetcher
232-
from garf_executors import api_executor
233-
from garf_io import reader
234-
235-
236-
# initialize query_executor to fetch report and store them in local/remote storage
237-
fake_report_fetcher = FakeApiReportFetcher(data=[{'campaign': {'id': 1}}])
238-
239-
query_executor = api_executor.ApiQueryExecutor(fetcher=fake_report_fetcher)
240-
241-
context = api_executor.ApiExecutionContext(writer='csv')
242-
243-
244-
query_text = "SELECT campaign.id AS campaign_id, FROM campaign"
245-
246-
# execute query and save results to `campaign.csv`
247-
query_executor.execute(query=query_text, title="campaign", context=context)
248-
249-
# execute query from file and save to results to `/tmp/query.csv`
250-
reader_client = reader.FileReader()
251-
query_path="path/to/query.sql"
252-
253-
query_executor.execute(
254-
query=reader_client.read(query_path),
255-
title=query_path,
256-
context=context
257-
)
258-
```
73+
[:octicons-arrow-right-24: More information](../usage/writers.md)

docs/get-started/server.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,23 @@ pip install garf-executors[server]
1313
```bash
1414
python garf_executors.entrypoints.server
1515
```
16+
17+
## Query
18+
19+
```
20+
curl -X 'POST' \
21+
'http://127.0.0.1:8000/api/execute' \
22+
-H 'accept: application/json' \
23+
-H 'Content-Type: application/json' \
24+
-d '{
25+
"source": "fake",
26+
"title": "example",
27+
"query": "SELECT campaign FROM campaign",
28+
"context": {
29+
"writer": "console",
30+
"writer_params": {
31+
"format": "json"
32+
}
33+
}
34+
}'
35+
```

docs/index.md

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,23 @@ The framework allows you to define SQL-like queries alongside aliases and custom
99
Based on such a query the library constructs the correct query to a reporting API of your choice, automatically extract all necessary fields from API schema
1010
and transform them into a structure suitable for writing data.
1111

12+
## Key features
1213

13-
<div id="centered-install-tabs" class="install-command-container" markdown="1">
14-
<p class="get-started-text" style="text-align: center;">Get started:</p>
15-
<p style="text-align: center;">
16-
<code>pip install garf-executors</code>
17-
</p>
18-
</div>
14+
* Uses SQL-like syntax to interact with reporting APIs
15+
* Built-in support for writing data into various local / remote storage
16+
* Available as library, CLI, FastAPI endpoint
17+
* Easily extendable to support various APIs
1918

2019

20+
## Installation
21+
```python
22+
pip install garf-executors
23+
```
24+
2125
`garf` consist of several core libraries:
2226

23-
* [`garf-core`](libs/garf_core) - exposes interfaces and core classes such as `GarfReport`.
24-
* [`garf-io`](libs/garf_io) - handles reading queries and writing `GarfReport` to various local/remote storages.
25-
* [`garf-executors`](libs/garf_executors) - responsible for orchestrating process of fetching from API and storing data in a storage.
27+
* [`garf-core`](https://github.com/google/garf/tree/main/libs/garf_core) - exposes interfaces and core classes such as `GarfReport`.
28+
* [`garf-io`](https://github.com/google/garf/tree/main/libs/garf_io) - handles reading queries and writing `GarfReport` to various local/remote storages.
29+
* [`garf-executors`](https://github.com/google/garf/tree/main/libs/garf_executors) - responsible for orchestrating process of fetching from API and storing data in a storage.
2630

27-
[`garf-community`](libs/garf_community) folder contains concrete implementation of the framework for various APIs.
31+
[`garf-community`](https://github.com/google/garf/tree/main/libs/garf_community) folder contains concrete implementation of the framework for various APIs.

0 commit comments

Comments
 (0)