sql_fusion 1.0.0__py3-none-any.whl

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.
@@ -0,0 +1,119 @@
1
+ from typing import Any, Callable
2
+
3
+ OPERATORS: dict[str, type[AbstractOperator]] = {}
4
+
5
+
6
+ class AbstractOperator:
7
+ sql_symbol: str = ""
8
+
9
+ def __init__(self, col_ref: str) -> None:
10
+ self._col_ref: str = col_ref
11
+
12
+ def to_sql(self, value: Any) -> tuple[str, tuple[Any, ...]]:
13
+ raise NotImplementedError()
14
+
15
+ def to_sql_ref(self, value_ref: str) -> tuple[str, tuple[Any, ...]]:
16
+ raise NotImplementedError()
17
+
18
+
19
+ def register_operator(
20
+ symbol: str,
21
+ ) -> Callable[[type[AbstractOperator]], type[AbstractOperator]]:
22
+ def decorator(cls: type[AbstractOperator]) -> type[AbstractOperator]:
23
+ OPERATORS[symbol] = cls
24
+ cls.sql_symbol = symbol
25
+ return cls
26
+
27
+ return decorator
28
+
29
+
30
+ @register_operator("=")
31
+ class EqualOperator(AbstractOperator):
32
+ def to_sql(self, value: Any) -> tuple[str, tuple[Any, ...]]:
33
+ return f"{self._col_ref} = ?", (value,)
34
+
35
+ def to_sql_ref(self, value_ref: str) -> tuple[str, tuple[Any, ...]]:
36
+ return f"{self._col_ref} = {value_ref}", tuple()
37
+
38
+
39
+ @register_operator("!=")
40
+ class NotEqualOperator(AbstractOperator):
41
+ def to_sql(self, value: Any) -> tuple[str, tuple[Any, ...]]:
42
+ return f"{self._col_ref} != ?", (value,)
43
+
44
+ def to_sql_ref(self, value_ref: str) -> tuple[str, tuple[Any, ...]]:
45
+ return f"{self._col_ref} != {value_ref}", tuple()
46
+
47
+
48
+ @register_operator("<")
49
+ class LessThanOperator(AbstractOperator):
50
+ def to_sql(self, value: Any) -> tuple[str, tuple[Any, ...]]:
51
+ return f"{self._col_ref} < ?", (value,)
52
+
53
+ def to_sql_ref(self, value_ref: str) -> tuple[str, tuple[Any, ...]]:
54
+ return f"{self._col_ref} < {value_ref}", tuple()
55
+
56
+
57
+ @register_operator(">")
58
+ class GreaterThanOperator(AbstractOperator):
59
+ def to_sql(self, value: Any) -> tuple[str, tuple[Any, ...]]:
60
+ return f"{self._col_ref} > ?", (value,)
61
+
62
+ def to_sql_ref(self, value_ref: str) -> tuple[str, tuple[Any, ...]]:
63
+ return f"{self._col_ref} > {value_ref}", tuple()
64
+
65
+
66
+ @register_operator("<=")
67
+ class LessThanOrEqualOperator(AbstractOperator):
68
+ def to_sql(self, value: Any) -> tuple[str, tuple[Any, ...]]:
69
+ return f"{self._col_ref} <= ?", (value,)
70
+
71
+ def to_sql_ref(self, value_ref: str) -> tuple[str, tuple[Any, ...]]:
72
+ return f"{self._col_ref} <= {value_ref}", tuple()
73
+
74
+
75
+ @register_operator(">=")
76
+ class GreaterThanOrEqualOperator(AbstractOperator):
77
+ def to_sql(self, value: Any) -> tuple[str, tuple[Any, ...]]:
78
+ return f"{self._col_ref} >= ?", (value,)
79
+
80
+ def to_sql_ref(self, value_ref: str) -> tuple[str, tuple[Any, ...]]:
81
+ return f"{self._col_ref} >= {value_ref}", tuple()
82
+
83
+
84
+ @register_operator("LIKE")
85
+ class LikeOperator(AbstractOperator):
86
+ def to_sql(self, value: Any) -> tuple[str, tuple[Any, ...]]:
87
+ return f"{self._col_ref} LIKE ?", (value,)
88
+
89
+ def to_sql_ref(self, value_ref: str) -> tuple[str, tuple[Any, ...]]:
90
+ return f"{self._col_ref} LIKE {value_ref}", tuple()
91
+
92
+
93
+ @register_operator("ILIKE")
94
+ class IlikeOperator(AbstractOperator):
95
+ def to_sql(self, value: Any) -> tuple[str, tuple[Any, ...]]:
96
+ return f"{self._col_ref} ILIKE ?", (value,)
97
+
98
+ def to_sql_ref(self, value_ref: str) -> tuple[str, tuple[Any, ...]]:
99
+ return f"{self._col_ref} ILIKE {value_ref}", tuple()
100
+
101
+
102
+ @register_operator("IN")
103
+ class InOperator(AbstractOperator):
104
+ def to_sql(self, value: Any) -> tuple[str, tuple[Any, ...]]:
105
+ placeholders: str = ", ".join("?" * len(value))
106
+ return f"{self._col_ref} IN ({placeholders})", tuple(value)
107
+
108
+ def to_sql_ref(self, value_ref: str) -> tuple[str, tuple[Any, ...]]:
109
+ return f"{self._col_ref} IN ({value_ref})", tuple()
110
+
111
+
112
+ @register_operator("NOT IN")
113
+ class NotInOperator(AbstractOperator):
114
+ def to_sql(self, value: Any) -> tuple[str, tuple[Any, ...]]:
115
+ placeholders: str = ", ".join("?" * len(value))
116
+ return f"{self._col_ref} NOT IN ({placeholders})", tuple(value)
117
+
118
+ def to_sql_ref(self, value_ref: str) -> tuple[str, tuple[Any, ...]]:
119
+ return f"{self._col_ref} NOT IN ({value_ref})", tuple()
File without changes
@@ -0,0 +1,84 @@
1
+ from copy import copy
2
+ from typing import Any, Self
3
+
4
+ from sql_fusion.composite_table import (
5
+ AbstractQuery,
6
+ AliasRegistry,
7
+ Column,
8
+ FunctionCall,
9
+ Table,
10
+ )
11
+
12
+
13
+ class delete(AbstractQuery):
14
+ def __init__(self, table: Table | None = None) -> None:
15
+ super().__init__(table=table, columns=())
16
+ self._returning_columns: tuple[Column | FunctionCall, ...] = ()
17
+ self._returning_all: bool = False
18
+
19
+ def returning(self, *columns: Column | FunctionCall) -> Self:
20
+ if not columns:
21
+ self._returning_all = True
22
+ self._returning_columns = ()
23
+ return self
24
+
25
+ if not self._returning_all:
26
+ self._returning_columns += columns
27
+
28
+ return self
29
+
30
+ def build_query(
31
+ self,
32
+ alias_registry: AliasRegistry | None = None,
33
+ ) -> tuple[str, tuple[Any, ...]]:
34
+ registry = alias_registry or self._alias_registry
35
+ table = self._get_table()
36
+ alias = registry.get_alias_for_table(table)
37
+ with_sql, with_params = self._build_with_clause(registry)
38
+ from_clause = self._build_clause(
39
+ "FROM",
40
+ "FROM",
41
+ f'"{table.get_name()}" AS "{alias.name}"',
42
+ )
43
+ query = self._build_clause("DELETE", "DELETE", from_clause)
44
+ params: list[Any] = list(with_params)
45
+
46
+ if self._where_condition:
47
+ where_sql, where_params = self._where_condition.to_sql(registry)
48
+ query += f" {self._build_clause('WHERE', 'WHERE', where_sql)}"
49
+ params.extend(where_params)
50
+
51
+ if self._returning_all:
52
+ query += f" {self._build_clause('RETURNING', 'RETURNING', '*')}"
53
+ return self._apply_compile_expressions(
54
+ f"{with_sql} {query}" if with_sql else query,
55
+ tuple(params),
56
+ )
57
+
58
+ if self._returning_columns:
59
+ returning_parts: list[str] = []
60
+
61
+ for col in self._returning_columns:
62
+ if isinstance(col, FunctionCall):
63
+ func_sql, func_params = col.to_sql(registry)
64
+ returning_parts.append(func_sql)
65
+ params.extend(func_params)
66
+ else:
67
+ alias = registry.get_alias_for_table(col.table)
68
+ returning_parts.append(f'"{alias.name}"."{col.name}"')
69
+
70
+ query += " " + self._build_clause(
71
+ "RETURNING",
72
+ "RETURNING",
73
+ ", ".join(returning_parts),
74
+ )
75
+
76
+ return self._apply_compile_expressions(
77
+ f"{with_sql} {query}" if with_sql else query,
78
+ tuple(params),
79
+ )
80
+
81
+ def from_(self, table: Table | AbstractQuery) -> Self:
82
+ qs = copy(self)
83
+ qs._table = table if isinstance(table, Table) else Table(table)
84
+ return qs
@@ -0,0 +1,72 @@
1
+ from typing import Any, Self
2
+
3
+ from sql_fusion.composite_table import AbstractQuery, AliasRegistry, Table
4
+
5
+
6
+ class insert(AbstractQuery):
7
+ def __init__(
8
+ self,
9
+ table: Table,
10
+ *,
11
+ or_replace: bool = False,
12
+ or_ignore: bool = False,
13
+ ) -> None:
14
+ super().__init__(table=table, columns=())
15
+ self._values: dict[str, Any] = {}
16
+ self._or_replace: bool = or_replace
17
+ self._or_ignore: bool = or_ignore
18
+
19
+ def values(self, **values: Any) -> Self:
20
+ if not values:
21
+ raise ValueError("No values provided for insert")
22
+ self._values.update(values)
23
+ return self
24
+
25
+ def build_query(
26
+ self,
27
+ alias_registry: AliasRegistry | None = None,
28
+ ) -> tuple[str, tuple[Any, ...]]:
29
+ if not self._values:
30
+ raise ValueError("No values provided for insert")
31
+ registry = alias_registry or self._alias_registry
32
+ table = self._get_table()
33
+ with_sql, with_params = self._build_with_clause(registry)
34
+
35
+ columns = list(self._values.keys())
36
+ col_names = ", ".join(f'"{col}"' for col in columns)
37
+ placeholders = ", ".join("?" * len(columns))
38
+ params = tuple(self._values[col] for col in columns)
39
+
40
+ insert_stmnt = "INSERT"
41
+
42
+ if self._or_replace and self._or_ignore:
43
+ raise ValueError("Cannot use both or_replace and or_ignore")
44
+ if self._or_replace:
45
+ insert_stmnt += " OR REPLACE"
46
+ elif self._or_ignore:
47
+ insert_stmnt += " OR IGNORE"
48
+
49
+ into_clause = self._build_clause(
50
+ "INTO",
51
+ "INTO",
52
+ f'"{table.get_name()}" ({col_names})',
53
+ )
54
+ values_clause = self._build_clause(
55
+ "VALUES",
56
+ "VALUES",
57
+ f"({placeholders})",
58
+ )
59
+ query = self._build_clause(
60
+ "INSERT",
61
+ insert_stmnt,
62
+ f"{into_clause} {values_clause}",
63
+ )
64
+
65
+ query_parts = [query]
66
+ if with_sql:
67
+ query_parts.insert(0, with_sql)
68
+
69
+ return self._apply_compile_expressions(
70
+ " ".join(query_parts),
71
+ tuple(with_params) + params,
72
+ )