Skip to content

Commit c22b582

Browse files
chore: Refactor SQLExprDateTimeNamespace (#2951)
--------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent a770e70 commit c22b582

File tree

6 files changed

+60
-84
lines changed

6 files changed

+60
-84
lines changed

narwhals/_duckdb/expr_dt.py

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
from typing import TYPE_CHECKING
44

5-
from narwhals._compliant import LazyExprNamespace
6-
from narwhals._compliant.any_namespace import DateTimeNamespace
75
from narwhals._constants import (
86
MS_PER_MINUTE,
97
MS_PER_SECOND,
@@ -14,6 +12,7 @@
1412
)
1513
from narwhals._duckdb.utils import UNITS_DICT, F, fetch_rel_time_zone, lit
1614
from narwhals._duration import Interval
15+
from narwhals._sql.expr_dt import SQLExprDateTimeNamesSpace
1716
from narwhals._utils import not_implemented
1817

1918
if TYPE_CHECKING:
@@ -25,27 +24,7 @@
2524
from narwhals._duckdb.expr import DuckDBExpr
2625

2726

28-
class DuckDBExprDateTimeNamespace(
29-
LazyExprNamespace["DuckDBExpr"], DateTimeNamespace["DuckDBExpr"]
30-
):
31-
def year(self) -> DuckDBExpr:
32-
return self.compliant._with_elementwise(lambda expr: F("year", expr))
33-
34-
def month(self) -> DuckDBExpr:
35-
return self.compliant._with_elementwise(lambda expr: F("month", expr))
36-
37-
def day(self) -> DuckDBExpr:
38-
return self.compliant._with_elementwise(lambda expr: F("day", expr))
39-
40-
def hour(self) -> DuckDBExpr:
41-
return self.compliant._with_elementwise(lambda expr: F("hour", expr))
42-
43-
def minute(self) -> DuckDBExpr:
44-
return self.compliant._with_elementwise(lambda expr: F("minute", expr))
45-
46-
def second(self) -> DuckDBExpr:
47-
return self.compliant._with_elementwise(lambda expr: F("second", expr))
48-
27+
class DuckDBExprDateTimeNamespace(SQLExprDateTimeNamesSpace["DuckDBExpr"]):
4928
def millisecond(self) -> DuckDBExpr:
5029
return self.compliant._with_elementwise(
5130
lambda expr: F("millisecond", expr) - F("second", expr) * lit(MS_PER_SECOND)
@@ -69,9 +48,6 @@ def to_string(self, format: str) -> DuckDBExpr:
6948
def weekday(self) -> DuckDBExpr:
7049
return self.compliant._with_elementwise(lambda expr: F("isodow", expr))
7150

72-
def ordinal_day(self) -> DuckDBExpr:
73-
return self.compliant._with_elementwise(lambda expr: F("dayofyear", expr))
74-
7551
def date(self) -> DuckDBExpr:
7652
return self.compliant._with_elementwise(lambda expr: expr.cast("date"))
7753

narwhals/_ibis/expr_dt.py

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@
22

33
from typing import TYPE_CHECKING, Any, Callable
44

5-
from narwhals._compliant import LazyExprNamespace
6-
from narwhals._compliant.any_namespace import DateTimeNamespace
75
from narwhals._duration import Interval
86
from narwhals._ibis.utils import (
97
UNITS_DICT_BUCKET,
108
UNITS_DICT_TRUNCATE,
119
timedelta_to_ibis_interval,
1210
)
11+
from narwhals._sql.expr_dt import SQLExprDateTimeNamesSpace
1312
from narwhals._utils import not_implemented
1413

1514
if TYPE_CHECKING:
@@ -19,27 +18,7 @@
1918
from narwhals._ibis.utils import BucketUnit, TruncateUnit
2019

2120

22-
class IbisExprDateTimeNamespace(
23-
LazyExprNamespace["IbisExpr"], DateTimeNamespace["IbisExpr"]
24-
):
25-
def year(self) -> IbisExpr:
26-
return self.compliant._with_callable(lambda expr: expr.year())
27-
28-
def month(self) -> IbisExpr:
29-
return self.compliant._with_callable(lambda expr: expr.month())
30-
31-
def day(self) -> IbisExpr:
32-
return self.compliant._with_callable(lambda expr: expr.day())
33-
34-
def hour(self) -> IbisExpr:
35-
return self.compliant._with_callable(lambda expr: expr.hour())
36-
37-
def minute(self) -> IbisExpr:
38-
return self.compliant._with_callable(lambda expr: expr.minute())
39-
40-
def second(self) -> IbisExpr:
41-
return self.compliant._with_callable(lambda expr: expr.second())
42-
21+
class IbisExprDateTimeNamespace(SQLExprDateTimeNamesSpace["IbisExpr"]):
4322
def millisecond(self) -> IbisExpr:
4423
return self.compliant._with_callable(lambda expr: expr.millisecond())
4524

@@ -53,12 +32,6 @@ def weekday(self) -> IbisExpr:
5332
# Ibis uses 0-6 for Monday-Sunday. Add 1 to match polars.
5433
return self.compliant._with_callable(lambda expr: expr.day_of_week.index() + 1)
5534

56-
def ordinal_day(self) -> IbisExpr:
57-
return self.compliant._with_callable(lambda expr: expr.day_of_year())
58-
59-
def date(self) -> IbisExpr:
60-
return self.compliant._with_callable(lambda expr: expr.date())
61-
6235
def _bucket(self, kwds: dict[BucketUnit, Any], /) -> Callable[..., ir.TimestampValue]:
6336
def fn(expr: ir.TimestampValue) -> ir.TimestampValue:
6437
return expr.bucket(**kwds)

narwhals/_ibis/utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@
7474
"ends_with": "endswith",
7575
"regexp_matches": "re_search",
7676
"str_split": "split",
77+
"dayofyear": "day_of_year",
78+
"to_date": "date",
7779
}
7880

7981

narwhals/_spark_like/expr_dt.py

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@
22

33
from typing import TYPE_CHECKING
44

5-
from narwhals._compliant import LazyExprNamespace
6-
from narwhals._compliant.any_namespace import DateTimeNamespace
75
from narwhals._constants import US_PER_SECOND
86
from narwhals._duration import Interval
97
from narwhals._spark_like.utils import (
108
UNITS_DICT,
119
fetch_session_time_zone,
1210
strptime_to_pyspark_format,
1311
)
12+
from narwhals._sql.expr_dt import SQLExprDateTimeNamesSpace
1413
from narwhals._utils import not_implemented
1514

1615
if TYPE_CHECKING:
@@ -22,9 +21,7 @@
2221
from narwhals._spark_like.expr import SparkLikeExpr
2322

2423

25-
class SparkLikeExprDateTimeNamespace(
26-
LazyExprNamespace["SparkLikeExpr"], DateTimeNamespace["SparkLikeExpr"]
27-
):
24+
class SparkLikeExprDateTimeNamespace(SQLExprDateTimeNamesSpace["SparkLikeExpr"]):
2825
def _weekday(self, expr: Column) -> Column:
2926
# PySpark's dayofweek returns 1-7 for Sunday-Saturday
3027
return (self.compliant._F.dayofweek(expr) + 6) % 7
@@ -63,27 +60,6 @@ def _to_string(expr: Column) -> Column:
6360

6461
return self.compliant._with_elementwise(_to_string)
6562

66-
def date(self) -> SparkLikeExpr:
67-
return self.compliant._with_elementwise(self.compliant._F.to_date)
68-
69-
def year(self) -> SparkLikeExpr:
70-
return self.compliant._with_elementwise(self.compliant._F.year)
71-
72-
def month(self) -> SparkLikeExpr:
73-
return self.compliant._with_elementwise(self.compliant._F.month)
74-
75-
def day(self) -> SparkLikeExpr:
76-
return self.compliant._with_elementwise(self.compliant._F.day)
77-
78-
def hour(self) -> SparkLikeExpr:
79-
return self.compliant._with_elementwise(self.compliant._F.hour)
80-
81-
def minute(self) -> SparkLikeExpr:
82-
return self.compliant._with_elementwise(self.compliant._F.minute)
83-
84-
def second(self) -> SparkLikeExpr:
85-
return self.compliant._with_elementwise(self.compliant._F.second)
86-
8763
def millisecond(self) -> SparkLikeExpr:
8864
def _millisecond(expr: Column) -> Column:
8965
return self.compliant._F.floor(
@@ -104,9 +80,6 @@ def _nanosecond(expr: Column) -> Column:
10480

10581
return self.compliant._with_elementwise(_nanosecond)
10682

107-
def ordinal_day(self) -> SparkLikeExpr:
108-
return self.compliant._with_elementwise(self.compliant._F.dayofyear)
109-
11083
def weekday(self) -> SparkLikeExpr:
11184
return self.compliant._with_elementwise(self._weekday)
11285

narwhals/_sql/expr.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
from narwhals._compliant.typing import AliasNames, WindowFunction
2929
from narwhals._expression_parsing import ExprMetadata
30+
from narwhals._sql.expr_dt import SQLExprDateTimeNamesSpace
3031
from narwhals._sql.expr_str import SQLExprStringNamespace
3132
from narwhals._sql.namespace import SQLNamespace
3233
from narwhals.typing import NumericLiteral, PythonLiteral, RankMethod, TemporalLiteral
@@ -744,6 +745,9 @@ def func(df: SQLLazyFrameT) -> Sequence[NativeExprT]:
744745
@property
745746
def str(self) -> SQLExprStringNamespace[Self]: ...
746747

748+
@property
749+
def dt(self) -> SQLExprDateTimeNamesSpace[Self]: ...
750+
747751
# Not implemented
748752

749753
arg_max: not_implemented = not_implemented()

narwhals/_sql/expr_dt.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from __future__ import annotations
2+
3+
from typing import Any, Generic
4+
5+
from narwhals._compliant import LazyExprNamespace
6+
from narwhals._compliant.any_namespace import DateTimeNamespace
7+
from narwhals._sql.typing import SQLExprT
8+
9+
10+
class SQLExprDateTimeNamesSpace(
11+
LazyExprNamespace[SQLExprT], DateTimeNamespace[SQLExprT], Generic[SQLExprT]
12+
):
13+
def _function(self, name: str, *args: Any) -> SQLExprT:
14+
return self.compliant._function(name, *args) # type: ignore[no-any-return]
15+
16+
def year(self) -> SQLExprT:
17+
return self.compliant._with_elementwise(lambda expr: self._function("year", expr))
18+
19+
def month(self) -> SQLExprT:
20+
return self.compliant._with_elementwise(
21+
lambda expr: self._function("month", expr)
22+
)
23+
24+
def day(self) -> SQLExprT:
25+
return self.compliant._with_elementwise(lambda expr: self._function("day", expr))
26+
27+
def hour(self) -> SQLExprT:
28+
return self.compliant._with_elementwise(lambda expr: self._function("hour", expr))
29+
30+
def minute(self) -> SQLExprT:
31+
return self.compliant._with_elementwise(
32+
lambda expr: self._function("minute", expr)
33+
)
34+
35+
def second(self) -> SQLExprT:
36+
return self.compliant._with_elementwise(
37+
lambda expr: self._function("second", expr)
38+
)
39+
40+
def ordinal_day(self) -> SQLExprT:
41+
return self.compliant._with_elementwise(
42+
lambda expr: self._function("dayofyear", expr)
43+
)
44+
45+
def date(self) -> SQLExprT:
46+
return self.compliant._with_elementwise(
47+
lambda expr: self._function("to_date", expr)
48+
)

0 commit comments

Comments
 (0)