-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathsql.py
More file actions
63 lines (50 loc) · 2.43 KB
/
Copy pathsql.py
File metadata and controls
63 lines (50 loc) · 2.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import xarray as xr
from datafusion import SessionContext
from . import cftime as cft
from .df import Chunks
from .reader import read_xarray_table
class XarrayContext(SessionContext):
"""A datafusion `SessionContext` that also supports `xarray.Dataset`s."""
def from_dataset(
self,
table_name: str,
input_table: xr.Dataset,
chunks: Chunks = None,
):
"""Register an xarray Dataset as a queryable SQL table.
For datasets with non-Gregorian cftime coordinates (e.g. 360_day,
julian), a ``cftime()`` scalar UDF is automatically registered so
you can write ergonomic SQL filters::
ctx.from_dataset("ds360", ds, chunks={"time": 6})
ctx.sql("SELECT * FROM ds360 WHERE time >= cftime('2000-07-01')")
The UDF converts a date string to the int64 offset used to store
that calendar's time axis.
.. note::
Only one ``cftime()`` UDF is registered per context, using the
units and calendar of the *first* non-Gregorian coordinate
encountered. If you register multiple datasets with *different*
non-Gregorian calendars (e.g. one 360_day and one julian), the
UDF from the first registration will be used for all subsequent
``cftime()`` calls and may produce incorrect offsets for the
other dataset. In that case, create a separate ``XarrayContext``
for each calendar.
Args:
table_name: The SQL table name to register the dataset under.
input_table: An xarray Dataset. All data_vars must share the
same dimensions.
chunks: Xarray-like chunks specification. If not provided, uses
the Dataset's existing chunks.
Returns:
self, to allow chaining.
"""
table = read_xarray_table(input_table, chunks)
self.register_table(table_name, table)
# Auto-register a cftime() UDF for non-Gregorian cftime coordinates
# so users can write: WHERE time > cftime('0500-01-01')
for coord_name in input_table.dims:
if cft.is_cftime_index(input_table, coord_name):
units, cal = cft.encoding(input_table, coord_name)
if not cft.is_gregorian_like(cal):
self.register_udf(cft.make_cftime_udf(units, cal))
break # One UDF per context is enough.
return self