graphique 2.0.2__tar.gz → 2.2__tar.gz
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.
- {graphique-2.0.2 → graphique-2.2}/PKG-INFO +43 -33
- {graphique-2.0.2 → graphique-2.2}/README.md +32 -25
- graphique-2.2/graphique/__init__.py +21 -0
- graphique-2.2/graphique/ducklake.py +41 -0
- {graphique-2.0.2 → graphique-2.2}/graphique/inputs.py +133 -71
- graphique-2.2/graphique/interface.py +578 -0
- graphique-2.2/graphique/middleware.py +169 -0
- {graphique-2.0.2 → graphique-2.2}/graphique/models.py +46 -52
- graphique-2.2/graphique/partition.py +62 -0
- {graphique-2.0.2 → graphique-2.2}/graphique/scalars.py +47 -3
- graphique-2.2/graphique/service.py +38 -0
- {graphique-2.0.2 → graphique-2.2}/graphique.egg-info/PKG-INFO +43 -33
- {graphique-2.0.2 → graphique-2.2}/graphique.egg-info/SOURCES.txt +2 -2
- {graphique-2.0.2 → graphique-2.2}/graphique.egg-info/requires.txt +6 -3
- {graphique-2.0.2 → graphique-2.2}/pyproject.toml +22 -19
- {graphique-2.0.2 → graphique-2.2}/tests/test_core.py +27 -15
- graphique-2.2/tests/test_dataset.py +177 -0
- {graphique-2.0.2 → graphique-2.2}/tests/test_models.py +25 -5
- {graphique-2.0.2 → graphique-2.2}/tests/test_service.py +100 -17
- graphique-2.0.2/graphique/__init__.py +0 -3
- graphique-2.0.2/graphique/core.py +0 -83
- graphique-2.0.2/graphique/interface.py +0 -383
- graphique-2.0.2/graphique/middleware.py +0 -125
- graphique-2.0.2/graphique/service.py +0 -44
- graphique-2.0.2/graphique/shell.py +0 -83
- graphique-2.0.2/tests/test_dataset.py +0 -167
- {graphique-2.0.2 → graphique-2.2}/LICENSE.txt +0 -0
- {graphique-2.0.2 → graphique-2.2}/graphique/py.typed +0 -0
- {graphique-2.0.2 → graphique-2.2}/graphique.egg-info/dependency_links.txt +0 -0
- {graphique-2.0.2 → graphique-2.2}/graphique.egg-info/top_level.txt +0 -0
- {graphique-2.0.2 → graphique-2.2}/setup.cfg +0 -0
|
@@ -1,41 +1,44 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: graphique
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2
|
|
4
4
|
Summary: GraphQL service for python dataframes and parquet datasets.
|
|
5
|
-
Author
|
|
5
|
+
Author: A. Coady
|
|
6
6
|
License-Expression: Apache-2.0
|
|
7
7
|
Project-URL: Homepage, https://github.com/coady/graphique
|
|
8
8
|
Project-URL: Documentation, https://coady.github.io/graphique
|
|
9
9
|
Project-URL: Changelog, https://github.com/coady/graphique/blob/main/CHANGELOG.md
|
|
10
10
|
Project-URL: Issues, https://github.com/coady/graphique/issues
|
|
11
|
-
Keywords: graphql,arrow,parquet
|
|
11
|
+
Keywords: graphql,ibis,dataframes,arrow,parquet,duckdb
|
|
12
12
|
Classifier: Development Status :: 5 - Production/Stable
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: Intended Audience :: Science/Research
|
|
15
15
|
Classifier: Operating System :: OS Independent
|
|
16
16
|
Classifier: Programming Language :: Python :: 3
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
21
21
|
Classifier: Topic :: Database :: Database Engines/Servers
|
|
22
22
|
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
23
23
|
Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
|
|
24
24
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
25
25
|
Classifier: Typing :: Typed
|
|
26
|
-
Requires-Python: >=3.
|
|
26
|
+
Requires-Python: >=3.12
|
|
27
27
|
Description-Content-Type: text/markdown
|
|
28
28
|
License-File: LICENSE.txt
|
|
29
|
-
Requires-Dist: pyarrow>=
|
|
30
|
-
Requires-Dist: strawberry-graphql[asgi,cli]>=0.
|
|
29
|
+
Requires-Dist: pyarrow>=23
|
|
30
|
+
Requires-Dist: strawberry-graphql[asgi,cli]>=0.328.3
|
|
31
31
|
Requires-Dist: ibis-framework>=10.7
|
|
32
|
-
Requires-Dist: pyarrow-hotfix
|
|
33
32
|
Requires-Dist: isodate>=0.7
|
|
33
|
+
Requires-Dist: pyarrow-hotfix
|
|
34
|
+
Requires-Dist: sqlglot<30.18
|
|
34
35
|
Provides-Extra: server
|
|
35
36
|
Requires-Dist: uvicorn[standard]; extra == "server"
|
|
36
37
|
Requires-Dist: duckdb; extra == "server"
|
|
37
38
|
Provides-Extra: cli
|
|
39
|
+
Requires-Dist: duckdb; extra == "cli"
|
|
38
40
|
Requires-Dist: tqdm; extra == "cli"
|
|
41
|
+
Requires-Dist: typer; extra == "cli"
|
|
39
42
|
Dynamic: license-file
|
|
40
43
|
|
|
41
44
|
[](https://pypi.org/project/graphique/)
|
|
@@ -48,14 +51,9 @@ Dynamic: license-file
|
|
|
48
51
|
[](https://github.com/astral-sh/ruff)
|
|
49
52
|
[](https://github.com/astral-sh/ty)
|
|
50
53
|
|
|
51
|
-
[GraphQL](https://graphql.org) service for [ibis](https://ibis-project.org)
|
|
52
|
-
|
|
53
|
-
## Version 2
|
|
54
|
-
When this project started, there was no out-of-core execution engine with performance comparable to [PyArrow](https://arrow.apache.org/docs/python/index.html). So it effectively included one, based on datasets and [Acero](https://arrow.apache.org/docs/python/api/acero.html).
|
|
54
|
+
[GraphQL](https://graphql.org) service for [ibis](https://ibis-project.org) tables. Ibis supports [20+ backends](https://ibis-project.org/why#how-does-ibis-work) — DuckDB, PostgreSQL, Polars, BigQuery, etc. — so the same query API works across local files and remote databases. The schema is derived automatically.
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
Being a major version upgrade, there are incompatible changes from version 1. However the overall API remains largely the same.
|
|
56
|
+
[Parquet](https://parquet.apache.org) files load with `ibis.read_parquet`. For hive-partitioned data, [DuckLake](https://ducklake.select/) (`graphique.ducklake.register` / `attach`) keeps partition metadata in a catalog so DuckDB can prune and count without scanning footers. Passing a PyArrow `Dataset` as a root is deprecated.
|
|
59
57
|
|
|
60
58
|
## Usage
|
|
61
59
|
There is an example app which reads a parquet dataset.
|
|
@@ -74,25 +72,30 @@ outputs the graphql schema.
|
|
|
74
72
|
The example app uses [Starlette's config](https://www.starlette.io/config/): in environment variables or a `.env` file.
|
|
75
73
|
|
|
76
74
|
* PARQUET_PATH: path to the parquet directory or file
|
|
77
|
-
*
|
|
78
|
-
* METRICS = False: include timings from apollo tracing extension
|
|
75
|
+
* NAME = '': GraphQL field on `Query`; defaults to root type
|
|
79
76
|
* COLUMNS = None: list of names, or mapping of aliases, of columns to select
|
|
80
|
-
* FILTERS = None: json `filter` query for which rows to read at startup
|
|
81
77
|
|
|
82
78
|
Configuration options exist to provide a convenient no-code solution, but are subject to change in the future. Using a custom app is recommended for production usage.
|
|
83
79
|
|
|
84
80
|
### App
|
|
85
|
-
For more options create a custom [ASGI](https://asgi.readthedocs.io/en/latest/index.html) app. Call graphique's `GraphQL` on an ibis [Table](https://ibis-project.org/reference/expression-tables)
|
|
86
|
-
|
|
81
|
+
For more options create a custom [ASGI](https://asgi.readthedocs.io/en/latest/index.html) app. Call graphique's `GraphQL` on an ibis [Table](https://ibis-project.org/reference/expression-tables).
|
|
82
|
+
Use a `Query` type with table attributes for multiple roots, and to enable federation.
|
|
87
83
|
|
|
88
84
|
```python
|
|
89
85
|
import ibis
|
|
90
|
-
from graphique import GraphQL
|
|
86
|
+
from graphique import GraphQL, typed
|
|
87
|
+
|
|
88
|
+
# any ibis backend: DuckDB, PostgreSQL, Polars, BigQuery, ...
|
|
89
|
+
table = ibis.read_parquet(...) # or `ibis.connect(...).table(...)`
|
|
90
|
+
app = GraphQL(table) # Table is root query type
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
#
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
|
|
93
|
+
# multiple named fields, with optional federation keys
|
|
94
|
+
class Query:
|
|
95
|
+
name = table # or `typed(table, name, keys=...)`
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
app = GraphQL(Query)
|
|
96
99
|
```
|
|
97
100
|
|
|
98
101
|
Start like any ASGI app.
|
|
@@ -103,7 +106,7 @@ uvicorn <module>:app
|
|
|
103
106
|
|
|
104
107
|
### API
|
|
105
108
|
#### types
|
|
106
|
-
* `Dataset`: interface
|
|
109
|
+
* `Dataset`: GraphQL interface over an ibis table.
|
|
107
110
|
* `Table`: implements the `Dataset` interface. Adds typed `row`, `columns`, and `filter` fields from introspecting the schema.
|
|
108
111
|
* `Column`: interface for an ibis column. Each data type has a corresponding column implementation: Boolean, Int, BigInt, Float, Decimal, Date, Datetime, Time, Duration, Base64, String, Array, Struct. All columns have a `values` field for their list of scalars. Additional fields vary by type.
|
|
109
112
|
* `Row`: scalar fields. Tables are column-oriented, and graphique encourages that usage for performance. A single `row` field is provided for convenience, but a field for a list of rows is not. Requesting parallel columns is far more efficient.
|
|
@@ -111,7 +114,8 @@ uvicorn <module>:app
|
|
|
111
114
|
#### selection
|
|
112
115
|
* `slice`: contiguous selection of rows
|
|
113
116
|
* `filter`: select rows by predicates
|
|
114
|
-
* `join`: join tables by key columns
|
|
117
|
+
* `join`, `asofJoin`, `crossJoin`: join tables by key columns
|
|
118
|
+
* `difference`, `intersect`, `union`: set operations on tables
|
|
115
119
|
* `take`: rows by index
|
|
116
120
|
* `dropNull`: remove rows with nulls
|
|
117
121
|
|
|
@@ -121,27 +125,33 @@ uvicorn <module>:app
|
|
|
121
125
|
* `column`: access a column of any type by name
|
|
122
126
|
* `row`: provides a field for each scalar of a single row
|
|
123
127
|
* `cast`: cast column types
|
|
128
|
+
* `unpack`: project struct fields
|
|
124
129
|
* `fillNull`: fill null values
|
|
125
130
|
|
|
126
131
|
#### aggregation
|
|
127
132
|
* `group`: group by given columns, and aggregate the others
|
|
128
133
|
* `distinct`: group with all columns
|
|
129
|
-
* `runs`:
|
|
134
|
+
* `runs`: group by adjacency
|
|
130
135
|
* `unnest`: unnest an array column
|
|
131
|
-
* `count`: number of rows
|
|
136
|
+
* `count`, `any`: number of rows
|
|
132
137
|
|
|
133
138
|
#### ordering
|
|
134
139
|
* `order`: sort table by given columns
|
|
135
|
-
*
|
|
140
|
+
* `first`: sort and filter by rank
|
|
141
|
+
|
|
142
|
+
#### reflection
|
|
143
|
+
* `schema`: field names and types
|
|
144
|
+
* `optional`: nullable for errors
|
|
145
|
+
* `toSql`: compiles SQL query
|
|
136
146
|
|
|
137
147
|
### Performance
|
|
138
|
-
Performance is dependent on the
|
|
148
|
+
Performance is dependent on the Ibis backend, which defaults to DuckDB. There are no internal Python loops. Scalars do not become Python types until serialized. Table fields are lazily evaluated up until scalars are reached, and automatically cached as needed for multiple fields.
|
|
139
149
|
|
|
140
|
-
[
|
|
150
|
+
For partitioned parquet datasets, [DuckLake](https://ducklake.select) provides performance benefits over `ibis.read_parquet`; see `graphique.ducklake.{register,attach}` for helpers. `python -m graphique.partition` in `graphique[cli]` writes hive-layout parquet out-of-core.
|
|
141
151
|
|
|
142
152
|
## Installation
|
|
143
153
|
```console
|
|
144
|
-
pip install graphique[server]
|
|
154
|
+
pip install graphique[server,cli]
|
|
145
155
|
```
|
|
146
156
|
|
|
147
157
|
## Dependencies
|
|
@@ -8,14 +8,9 @@
|
|
|
8
8
|
[](https://github.com/astral-sh/ruff)
|
|
9
9
|
[](https://github.com/astral-sh/ty)
|
|
10
10
|
|
|
11
|
-
[GraphQL](https://graphql.org) service for [ibis](https://ibis-project.org)
|
|
11
|
+
[GraphQL](https://graphql.org) service for [ibis](https://ibis-project.org) tables. Ibis supports [20+ backends](https://ibis-project.org/why#how-does-ibis-work) — DuckDB, PostgreSQL, Polars, BigQuery, etc. — so the same query API works across local files and remote databases. The schema is derived automatically.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
When this project started, there was no out-of-core execution engine with performance comparable to [PyArrow](https://arrow.apache.org/docs/python/index.html). So it effectively included one, based on datasets and [Acero](https://arrow.apache.org/docs/python/api/acero.html).
|
|
15
|
-
|
|
16
|
-
Since then the ecosystem has grown considerably: [DuckDB](https://duckdb.org), [DataFusion](https://datafusion.apache.org), and [Ibis](https://ibis-project.org). As of version 2, graphique is based on `ibis`. It provides a common dataframe API for multiple backends, enabling graphique to also have a default but configurable backend.
|
|
17
|
-
|
|
18
|
-
Being a major version upgrade, there are incompatible changes from version 1. However the overall API remains largely the same.
|
|
13
|
+
[Parquet](https://parquet.apache.org) files load with `ibis.read_parquet`. For hive-partitioned data, [DuckLake](https://ducklake.select/) (`graphique.ducklake.register` / `attach`) keeps partition metadata in a catalog so DuckDB can prune and count without scanning footers. Passing a PyArrow `Dataset` as a root is deprecated.
|
|
19
14
|
|
|
20
15
|
## Usage
|
|
21
16
|
There is an example app which reads a parquet dataset.
|
|
@@ -34,25 +29,30 @@ outputs the graphql schema.
|
|
|
34
29
|
The example app uses [Starlette's config](https://www.starlette.io/config/): in environment variables or a `.env` file.
|
|
35
30
|
|
|
36
31
|
* PARQUET_PATH: path to the parquet directory or file
|
|
37
|
-
*
|
|
38
|
-
* METRICS = False: include timings from apollo tracing extension
|
|
32
|
+
* NAME = '': GraphQL field on `Query`; defaults to root type
|
|
39
33
|
* COLUMNS = None: list of names, or mapping of aliases, of columns to select
|
|
40
|
-
* FILTERS = None: json `filter` query for which rows to read at startup
|
|
41
34
|
|
|
42
35
|
Configuration options exist to provide a convenient no-code solution, but are subject to change in the future. Using a custom app is recommended for production usage.
|
|
43
36
|
|
|
44
37
|
### App
|
|
45
|
-
For more options create a custom [ASGI](https://asgi.readthedocs.io/en/latest/index.html) app. Call graphique's `GraphQL` on an ibis [Table](https://ibis-project.org/reference/expression-tables)
|
|
46
|
-
|
|
38
|
+
For more options create a custom [ASGI](https://asgi.readthedocs.io/en/latest/index.html) app. Call graphique's `GraphQL` on an ibis [Table](https://ibis-project.org/reference/expression-tables).
|
|
39
|
+
Use a `Query` type with table attributes for multiple roots, and to enable federation.
|
|
47
40
|
|
|
48
41
|
```python
|
|
49
42
|
import ibis
|
|
50
|
-
from graphique import GraphQL
|
|
43
|
+
from graphique import GraphQL, typed
|
|
44
|
+
|
|
45
|
+
# any ibis backend: DuckDB, PostgreSQL, Polars, BigQuery, ...
|
|
46
|
+
table = ibis.read_parquet(...) # or `ibis.connect(...).table(...)`
|
|
47
|
+
app = GraphQL(table) # Table is root query type
|
|
48
|
+
|
|
51
49
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
# multiple named fields, with optional federation keys
|
|
51
|
+
class Query:
|
|
52
|
+
name = table # or `typed(table, name, keys=...)`
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
app = GraphQL(Query)
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
Start like any ASGI app.
|
|
@@ -63,7 +63,7 @@ uvicorn <module>:app
|
|
|
63
63
|
|
|
64
64
|
### API
|
|
65
65
|
#### types
|
|
66
|
-
* `Dataset`: interface
|
|
66
|
+
* `Dataset`: GraphQL interface over an ibis table.
|
|
67
67
|
* `Table`: implements the `Dataset` interface. Adds typed `row`, `columns`, and `filter` fields from introspecting the schema.
|
|
68
68
|
* `Column`: interface for an ibis column. Each data type has a corresponding column implementation: Boolean, Int, BigInt, Float, Decimal, Date, Datetime, Time, Duration, Base64, String, Array, Struct. All columns have a `values` field for their list of scalars. Additional fields vary by type.
|
|
69
69
|
* `Row`: scalar fields. Tables are column-oriented, and graphique encourages that usage for performance. A single `row` field is provided for convenience, but a field for a list of rows is not. Requesting parallel columns is far more efficient.
|
|
@@ -71,7 +71,8 @@ uvicorn <module>:app
|
|
|
71
71
|
#### selection
|
|
72
72
|
* `slice`: contiguous selection of rows
|
|
73
73
|
* `filter`: select rows by predicates
|
|
74
|
-
* `join`: join tables by key columns
|
|
74
|
+
* `join`, `asofJoin`, `crossJoin`: join tables by key columns
|
|
75
|
+
* `difference`, `intersect`, `union`: set operations on tables
|
|
75
76
|
* `take`: rows by index
|
|
76
77
|
* `dropNull`: remove rows with nulls
|
|
77
78
|
|
|
@@ -81,27 +82,33 @@ uvicorn <module>:app
|
|
|
81
82
|
* `column`: access a column of any type by name
|
|
82
83
|
* `row`: provides a field for each scalar of a single row
|
|
83
84
|
* `cast`: cast column types
|
|
85
|
+
* `unpack`: project struct fields
|
|
84
86
|
* `fillNull`: fill null values
|
|
85
87
|
|
|
86
88
|
#### aggregation
|
|
87
89
|
* `group`: group by given columns, and aggregate the others
|
|
88
90
|
* `distinct`: group with all columns
|
|
89
|
-
* `runs`:
|
|
91
|
+
* `runs`: group by adjacency
|
|
90
92
|
* `unnest`: unnest an array column
|
|
91
|
-
* `count`: number of rows
|
|
93
|
+
* `count`, `any`: number of rows
|
|
92
94
|
|
|
93
95
|
#### ordering
|
|
94
96
|
* `order`: sort table by given columns
|
|
95
|
-
*
|
|
97
|
+
* `first`: sort and filter by rank
|
|
98
|
+
|
|
99
|
+
#### reflection
|
|
100
|
+
* `schema`: field names and types
|
|
101
|
+
* `optional`: nullable for errors
|
|
102
|
+
* `toSql`: compiles SQL query
|
|
96
103
|
|
|
97
104
|
### Performance
|
|
98
|
-
Performance is dependent on the
|
|
105
|
+
Performance is dependent on the Ibis backend, which defaults to DuckDB. There are no internal Python loops. Scalars do not become Python types until serialized. Table fields are lazily evaluated up until scalars are reached, and automatically cached as needed for multiple fields.
|
|
99
106
|
|
|
100
|
-
[
|
|
107
|
+
For partitioned parquet datasets, [DuckLake](https://ducklake.select) provides performance benefits over `ibis.read_parquet`; see `graphique.ducklake.{register,attach}` for helpers. `python -m graphique.partition` in `graphique[cli]` writes hive-layout parquet out-of-core.
|
|
101
108
|
|
|
102
109
|
## Installation
|
|
103
110
|
```console
|
|
104
|
-
pip install graphique[server]
|
|
111
|
+
pip install graphique[server,cli]
|
|
105
112
|
```
|
|
106
113
|
|
|
107
114
|
## Dependencies
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from .interface import Dataset
|
|
2
|
+
from .middleware import GraphQL, MetricsExtension, implement, typed
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def fetch_record_batch(self, rows_per_batch):
|
|
6
|
+
return self.to_arrow_reader(rows_per_batch)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def connect(database=":memory:", read_only=False, config={}):
|
|
10
|
+
return original(database, read_only, {"lambda_syntax": "ENABLE_SINGLE_ARROW", **config})
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
import duckdb
|
|
15
|
+
except ImportError: # pragma: no cover
|
|
16
|
+
pass
|
|
17
|
+
else: # ibis-project/ibis#12196
|
|
18
|
+
if not hasattr(duckdb.DuckDBPyConnection, "fetch_arrow_table"): # pragma: no branch
|
|
19
|
+
duckdb.DuckDBPyConnection.fetch_arrow_table = duckdb.DuckDBPyConnection.to_arrow_table
|
|
20
|
+
duckdb.DuckDBPyConnection.fetch_record_batch = fetch_record_batch
|
|
21
|
+
original, duckdb.connect = duckdb.connect, connect # type: ignore
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""DuckLake helpers."""
|
|
2
|
+
|
|
3
|
+
import functools
|
|
4
|
+
from collections.abc import Sequence
|
|
5
|
+
|
|
6
|
+
import ibis
|
|
7
|
+
import pyarrow.dataset as ds
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@functools.singledispatch
|
|
11
|
+
def register(
|
|
12
|
+
source: str | Sequence[str],
|
|
13
|
+
table: str,
|
|
14
|
+
*partitioning: str,
|
|
15
|
+
catalog: str = ":memory:",
|
|
16
|
+
database: str = "lake.main",
|
|
17
|
+
) -> ibis.Table:
|
|
18
|
+
"""Attach a DuckLake catalog and register a parquet dataset."""
|
|
19
|
+
alias, _, schema = database.partition(".")
|
|
20
|
+
con = ibis.duckdb.connect(extensions=["ducklake"])
|
|
21
|
+
con.raw_sql(f"ATTACH 'ducklake:{catalog}' AS {alias}")
|
|
22
|
+
con.create_table(table, schema=con.read_parquet(source).schema(), database=database)
|
|
23
|
+
if columns := ", ".join(partitioning):
|
|
24
|
+
con.raw_sql(f"ALTER TABLE {database}.{table} SET PARTITIONED BY ({columns})")
|
|
25
|
+
parameters = alias, table, source, schema
|
|
26
|
+
con.raw_sql("CALL ducklake_add_data_files(?, ?, ?, schema => ?)", parameters=parameters)
|
|
27
|
+
return con.table(table, database=database)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@register.register
|
|
31
|
+
def _(source: ds.Dataset, table: str, filter: ds.Expression | None = None, **kwargs) -> ibis.Table:
|
|
32
|
+
paths = [frag.path for frag in source.get_fragments(filter)]
|
|
33
|
+
return register(paths, table, *source.partitioning.schema.names, **kwargs)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def attach(table: str, catalog: str, database: str = "lake.main") -> ibis.Table:
|
|
37
|
+
"""Attach a DuckLake catalog read-only and return a table."""
|
|
38
|
+
alias, _, _ = database.partition(".")
|
|
39
|
+
con = ibis.duckdb.connect(extensions=["ducklake"])
|
|
40
|
+
con.raw_sql(f"ATTACH 'ducklake:{catalog}' AS {alias} (READ_ONLY)")
|
|
41
|
+
return con.table(table, database=database)
|