relationalai 1.0.0a3__py3-none-any.whl → 1.0.0a5__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.
- relationalai/config/config.py +47 -21
- relationalai/config/connections/__init__.py +5 -2
- relationalai/config/connections/duckdb.py +2 -2
- relationalai/config/connections/local.py +31 -0
- relationalai/config/connections/snowflake.py +0 -1
- relationalai/config/external/raiconfig_converter.py +235 -0
- relationalai/config/external/raiconfig_models.py +202 -0
- relationalai/config/external/utils.py +31 -0
- relationalai/config/shims.py +1 -0
- relationalai/semantics/__init__.py +10 -8
- relationalai/semantics/backends/sql/sql_compiler.py +1 -4
- relationalai/semantics/experimental/__init__.py +0 -0
- relationalai/semantics/experimental/builder.py +295 -0
- relationalai/semantics/experimental/builtins.py +154 -0
- relationalai/semantics/frontend/base.py +67 -42
- relationalai/semantics/frontend/core.py +34 -6
- relationalai/semantics/frontend/front_compiler.py +209 -37
- relationalai/semantics/frontend/pprint.py +6 -2
- relationalai/semantics/metamodel/__init__.py +7 -0
- relationalai/semantics/metamodel/metamodel.py +2 -0
- relationalai/semantics/metamodel/metamodel_analyzer.py +58 -16
- relationalai/semantics/metamodel/pprint.py +6 -1
- relationalai/semantics/metamodel/rewriter.py +11 -7
- relationalai/semantics/metamodel/typer.py +116 -41
- relationalai/semantics/reasoners/__init__.py +11 -0
- relationalai/semantics/reasoners/graph/__init__.py +35 -0
- relationalai/semantics/reasoners/graph/core.py +9028 -0
- relationalai/semantics/std/__init__.py +30 -10
- relationalai/semantics/std/aggregates.py +641 -12
- relationalai/semantics/std/common.py +146 -13
- relationalai/semantics/std/constraints.py +71 -1
- relationalai/semantics/std/datetime.py +904 -21
- relationalai/semantics/std/decimals.py +143 -2
- relationalai/semantics/std/floats.py +57 -4
- relationalai/semantics/std/integers.py +98 -4
- relationalai/semantics/std/math.py +857 -35
- relationalai/semantics/std/numbers.py +216 -20
- relationalai/semantics/std/re.py +213 -5
- relationalai/semantics/std/strings.py +437 -44
- relationalai/shims/executor.py +60 -52
- relationalai/shims/fixtures.py +85 -0
- relationalai/shims/helpers.py +26 -2
- relationalai/shims/hoister.py +28 -9
- relationalai/shims/mm2v0.py +204 -173
- relationalai/tools/cli/cli.py +192 -10
- relationalai/tools/cli/components/progress_reader.py +1 -1
- relationalai/tools/cli/docs.py +394 -0
- relationalai/tools/debugger.py +11 -4
- relationalai/tools/qb_debugger.py +435 -0
- relationalai/tools/typer_debugger.py +1 -2
- relationalai/util/dataclasses.py +3 -5
- relationalai/util/docutils.py +1 -2
- relationalai/util/error.py +2 -5
- relationalai/util/python.py +23 -0
- relationalai/util/runtime.py +1 -2
- relationalai/util/schema.py +2 -4
- relationalai/util/structures.py +4 -2
- relationalai/util/tracing.py +8 -2
- {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/METADATA +8 -5
- {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/RECORD +118 -95
- {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/WHEEL +1 -1
- v0/relationalai/__init__.py +1 -1
- v0/relationalai/clients/client.py +52 -18
- v0/relationalai/clients/exec_txn_poller.py +122 -0
- v0/relationalai/clients/local.py +23 -8
- v0/relationalai/clients/resources/azure/azure.py +36 -11
- v0/relationalai/clients/resources/snowflake/__init__.py +4 -4
- v0/relationalai/clients/resources/snowflake/cli_resources.py +12 -1
- v0/relationalai/clients/resources/snowflake/direct_access_resources.py +124 -100
- v0/relationalai/clients/resources/snowflake/engine_service.py +381 -0
- v0/relationalai/clients/resources/snowflake/engine_state_handlers.py +35 -29
- v0/relationalai/clients/resources/snowflake/error_handlers.py +43 -2
- v0/relationalai/clients/resources/snowflake/snowflake.py +277 -179
- v0/relationalai/clients/resources/snowflake/use_index_poller.py +8 -0
- v0/relationalai/clients/types.py +5 -0
- v0/relationalai/errors.py +19 -1
- v0/relationalai/semantics/lqp/algorithms.py +173 -0
- v0/relationalai/semantics/lqp/builtins.py +199 -2
- v0/relationalai/semantics/lqp/executor.py +68 -37
- v0/relationalai/semantics/lqp/ir.py +28 -2
- v0/relationalai/semantics/lqp/model2lqp.py +215 -45
- v0/relationalai/semantics/lqp/passes.py +13 -658
- v0/relationalai/semantics/lqp/rewrite/__init__.py +12 -0
- v0/relationalai/semantics/lqp/rewrite/algorithm.py +385 -0
- v0/relationalai/semantics/lqp/rewrite/constants_to_vars.py +70 -0
- v0/relationalai/semantics/lqp/rewrite/deduplicate_vars.py +104 -0
- v0/relationalai/semantics/lqp/rewrite/eliminate_data.py +108 -0
- v0/relationalai/semantics/lqp/rewrite/extract_keys.py +25 -3
- v0/relationalai/semantics/lqp/rewrite/period_math.py +77 -0
- v0/relationalai/semantics/lqp/rewrite/quantify_vars.py +65 -31
- v0/relationalai/semantics/lqp/rewrite/unify_definitions.py +317 -0
- v0/relationalai/semantics/lqp/utils.py +11 -1
- v0/relationalai/semantics/lqp/validators.py +14 -1
- v0/relationalai/semantics/metamodel/builtins.py +2 -1
- v0/relationalai/semantics/metamodel/compiler.py +2 -1
- v0/relationalai/semantics/metamodel/dependency.py +12 -3
- v0/relationalai/semantics/metamodel/executor.py +11 -1
- v0/relationalai/semantics/metamodel/factory.py +2 -2
- v0/relationalai/semantics/metamodel/helpers.py +7 -0
- v0/relationalai/semantics/metamodel/ir.py +3 -2
- v0/relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +30 -20
- v0/relationalai/semantics/metamodel/rewrite/flatten.py +50 -13
- v0/relationalai/semantics/metamodel/rewrite/format_outputs.py +9 -3
- v0/relationalai/semantics/metamodel/typer/checker.py +6 -4
- v0/relationalai/semantics/metamodel/typer/typer.py +4 -3
- v0/relationalai/semantics/metamodel/visitor.py +4 -3
- v0/relationalai/semantics/reasoners/optimization/solvers_dev.py +1 -1
- v0/relationalai/semantics/reasoners/optimization/solvers_pb.py +336 -86
- v0/relationalai/semantics/rel/compiler.py +2 -1
- v0/relationalai/semantics/rel/executor.py +3 -2
- v0/relationalai/semantics/tests/lqp/__init__.py +0 -0
- v0/relationalai/semantics/tests/lqp/algorithms.py +345 -0
- v0/relationalai/tools/cli.py +339 -186
- v0/relationalai/tools/cli_controls.py +216 -67
- v0/relationalai/tools/cli_helpers.py +410 -6
- v0/relationalai/util/format.py +5 -2
- {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/entry_points.txt +0 -0
- {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/top_level.txt +0 -0
|
@@ -1,19 +1,31 @@
|
|
|
1
|
+
"""
|
|
2
|
+
String manipulation functions.
|
|
3
|
+
|
|
4
|
+
This module provides a comprehensive set of string operations including:
|
|
5
|
+
- String conversion and concatenation
|
|
6
|
+
- Case conversion and whitespace handling
|
|
7
|
+
- String splitting and substring extraction
|
|
8
|
+
- Distance metrics
|
|
9
|
+
- Pattern matching and searching
|
|
10
|
+
- Regular expression matching
|
|
11
|
+
"""
|
|
1
12
|
from __future__ import annotations
|
|
2
|
-
from decimal import Decimal as PyDecimal
|
|
3
13
|
|
|
4
14
|
from relationalai.semantics import Float
|
|
15
|
+
from relationalai.util.docutils import include_in_docs
|
|
5
16
|
|
|
6
|
-
from . import StringValue, IntegerValue,
|
|
7
|
-
from ..frontend.base import
|
|
17
|
+
from . import DateValue, StringValue, IntegerValue, FloatValue, NumberValue, DateTimeValue
|
|
18
|
+
from ..frontend.base import Library, Expression, Field, TupleVariable, Variable
|
|
8
19
|
from ..frontend.core import Date, DateTime, Number, String, Integer, Any
|
|
9
20
|
from typing import Sequence
|
|
10
|
-
|
|
21
|
+
|
|
22
|
+
__include_in_docs__ = True
|
|
11
23
|
|
|
12
24
|
# the front-end library object
|
|
13
25
|
library = Library("strings")
|
|
14
26
|
|
|
15
27
|
#--------------------------------------------------
|
|
16
|
-
#
|
|
28
|
+
# Operations
|
|
17
29
|
#--------------------------------------------------
|
|
18
30
|
|
|
19
31
|
_string = library.Relation("string", [Field.input("s", Any), Field("result", String)], overloads=[
|
|
@@ -23,96 +35,477 @@ _string = library.Relation("string", [Field.input("s", Any), Field("result", Str
|
|
|
23
35
|
[DateTime, String],
|
|
24
36
|
[Date, String],
|
|
25
37
|
])
|
|
26
|
-
_concat = library.Relation("concat", [Field.input("s1", String), Field.input("s2", String), Field("result", String)])
|
|
27
|
-
_contains = library.Relation("contains", [Field.input("s", String), Field.input("substr", String)])
|
|
28
|
-
_ends_with = library.Relation("ends_with", [Field.input("s", String), Field.input("suffix", String)])
|
|
29
|
-
_len = library.Relation("len", [Field.input("s", String), Field("result", Integer)])
|
|
30
|
-
_levenshtein = library.Relation("levenshtein", [Field.input("s1", String), Field.input("s2", String), Field("result", Integer)])
|
|
31
|
-
_like = library.Relation("like", [Field.input("s", String), Field.input("pattern", String)])
|
|
32
|
-
_lower = library.Relation("lower", [Field.input("s", String), Field("result", String)])
|
|
33
|
-
_replace = library.Relation("replace", [Field.input("source", String), Field.input("old", String), Field.input("new", String), Field("result", String)])
|
|
34
|
-
_starts_with = library.Relation("starts_with", [Field.input("s", String), Field.input("prefix", String)])
|
|
35
|
-
_split = library.Relation("split", [Field.input("s", String), Field.input("separator", String), Field("index", Integer), Field("result", String)])
|
|
36
|
-
_strip = library.Relation("strip", [Field.input("s", String), Field("result", String)])
|
|
37
|
-
_substring = library.Relation("substring", [Field.input("s", String), Field.input("start", Integer), Field.input("stop", Integer), Field("result", String)])
|
|
38
|
-
_upper = library.Relation("upper", [Field.input("s", String), Field("result", String)])
|
|
39
|
-
_regex_match = library.Relation("regex_match", [Field.input("regex", String), Field.input("value", String)])
|
|
40
|
-
_join = library.Relation("join", [Field.input("strs", String, is_list=True), Field.input("sep", String), Field("result", String)])
|
|
41
38
|
|
|
42
|
-
|
|
39
|
+
@include_in_docs
|
|
40
|
+
def string(s: StringValue|IntegerValue|FloatValue|NumberValue|DateTimeValue|DateValue) -> Expression:
|
|
41
|
+
"""
|
|
42
|
+
Convert a value to a string representation.
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
s: StringValue|IntegerValue|FloatValue|NumberValue|DateTimeValue|DateValue
|
|
47
|
+
The value to convert.
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
Expression
|
|
52
|
+
An `Expression` representing the `String` conversion of the input. Returns `String`.
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
Examples
|
|
55
|
+
--------
|
|
56
|
+
Convert various types to strings:
|
|
57
|
+
|
|
58
|
+
>>> strings.string(123)
|
|
59
|
+
>>> strings.string(3.14)
|
|
60
|
+
>>> strings.string(date(2024, 1, 15))
|
|
61
|
+
"""
|
|
49
62
|
return _string(s)
|
|
50
63
|
|
|
64
|
+
_concat = library.Relation("concat", [Field.input("s1", String), Field.input("s2", String), Field("result", String)])
|
|
65
|
+
|
|
66
|
+
@include_in_docs
|
|
51
67
|
def concat(s1: StringValue, s2: StringValue, *sn: StringValue) -> Expression:
|
|
52
|
-
"""
|
|
68
|
+
"""
|
|
69
|
+
Concatenate multiple strings together.
|
|
70
|
+
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
s1: StringValue
|
|
74
|
+
The first string to concatenate.
|
|
75
|
+
s2: StringValue
|
|
76
|
+
The second string to concatenate.
|
|
77
|
+
*sn: StringValue
|
|
78
|
+
Additional strings to concatenate.
|
|
79
|
+
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
Expression
|
|
83
|
+
An `Expression` representing the concatenated string. Returns `String`.
|
|
84
|
+
|
|
85
|
+
Examples
|
|
86
|
+
--------
|
|
87
|
+
Concatenate strings together:
|
|
88
|
+
|
|
89
|
+
>>> strings.concat("thing_", Thing.name)
|
|
90
|
+
>>> strings.concat("Hello", " ", "World")
|
|
91
|
+
"""
|
|
53
92
|
res = _concat(s1, s2, String.ref("res0"))
|
|
54
93
|
for i, s in enumerate(sn):
|
|
55
94
|
res = _concat(res, s, String.ref(f"res{i + 1}"))
|
|
56
95
|
return res
|
|
57
96
|
|
|
97
|
+
_join = library.Relation("join", [Field.input("strs", String, is_list=True), Field.input("sep", String), Field("result", String)])
|
|
98
|
+
|
|
99
|
+
@include_in_docs
|
|
58
100
|
def join(strs: Sequence[StringValue], separator: str = "") -> Expression:
|
|
101
|
+
"""
|
|
102
|
+
Join a sequence of strings with a separator.
|
|
103
|
+
|
|
104
|
+
Parameters
|
|
105
|
+
----------
|
|
106
|
+
strs: Sequence[StringValue]
|
|
107
|
+
A sequence of string values to join.
|
|
108
|
+
separator: str
|
|
109
|
+
The separator to use between strings.
|
|
110
|
+
|
|
111
|
+
Returns
|
|
112
|
+
-------
|
|
113
|
+
Expression
|
|
114
|
+
An `Expression` representing the joined string. Returns `String`.
|
|
115
|
+
|
|
116
|
+
Examples
|
|
117
|
+
--------
|
|
118
|
+
Join strings with various separators:
|
|
119
|
+
|
|
120
|
+
>>> strings.join(["FIRST", "MIDDLE", "LAST"]) # defaults to empty string separator
|
|
121
|
+
>>> strings.join([Person.first, Person.last], " ")
|
|
122
|
+
>>> strings.join([Person.first, "the best", Person.last], " | ")
|
|
123
|
+
"""
|
|
59
124
|
return _join(TupleVariable(strs), separator)
|
|
60
125
|
|
|
126
|
+
_contains = library.Relation("contains", [Field.input("s", String), Field.input("substr", String)])
|
|
127
|
+
|
|
128
|
+
@include_in_docs
|
|
61
129
|
def contains(s: StringValue, substr: StringValue) -> Expression:
|
|
62
|
-
"""
|
|
130
|
+
"""
|
|
131
|
+
Check whether `substr` is contained within `s`.
|
|
132
|
+
|
|
133
|
+
Parameters
|
|
134
|
+
----------
|
|
135
|
+
s: StringValue
|
|
136
|
+
The string to search in.
|
|
137
|
+
substr: StringValue
|
|
138
|
+
The substring to search for.
|
|
139
|
+
|
|
140
|
+
Returns
|
|
141
|
+
-------
|
|
142
|
+
Expression
|
|
143
|
+
An `Expression` that evaluates to `true` if `substr` is found in `s`.
|
|
144
|
+
|
|
145
|
+
Examples
|
|
146
|
+
--------
|
|
147
|
+
Check if a string contains a substring:
|
|
148
|
+
|
|
149
|
+
>>> select(Person.name).where(strings.contains(Person.last_name, "ohn"))
|
|
150
|
+
"""
|
|
63
151
|
return _contains(s, substr)
|
|
64
152
|
|
|
153
|
+
_ends_with = library.Relation("ends_with", [Field.input("s", String), Field.input("suffix", String)])
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
_starts_with = library.Relation("starts_with", [Field.input("s", String), Field.input("prefix", String)])
|
|
157
|
+
|
|
158
|
+
@include_in_docs
|
|
159
|
+
def startswith(s: StringValue, prefix: StringValue) -> Expression:
|
|
160
|
+
"""
|
|
161
|
+
Check whether `s` starts with `prefix`.
|
|
162
|
+
|
|
163
|
+
Parameters
|
|
164
|
+
----------
|
|
165
|
+
s: StringValue
|
|
166
|
+
The string to check.
|
|
167
|
+
prefix: StringValue
|
|
168
|
+
The prefix to check for.
|
|
169
|
+
|
|
170
|
+
Returns
|
|
171
|
+
-------
|
|
172
|
+
Expression
|
|
173
|
+
An `Expression` that evaluates to `true` if `s` starts with `prefix`.
|
|
174
|
+
|
|
175
|
+
Examples
|
|
176
|
+
--------
|
|
177
|
+
Filter strings that start with a prefix:
|
|
178
|
+
|
|
179
|
+
>>> select(Person.name).where(strings.startswith(Person.last_name, Person.name))
|
|
180
|
+
"""
|
|
181
|
+
return _starts_with(s, prefix)
|
|
182
|
+
|
|
183
|
+
@include_in_docs
|
|
65
184
|
def endswith(s: StringValue, suffix: StringValue) -> Expression:
|
|
66
|
-
"""
|
|
185
|
+
"""
|
|
186
|
+
Check whether `s` ends with `suffix`.
|
|
187
|
+
|
|
188
|
+
Parameters
|
|
189
|
+
----------
|
|
190
|
+
s: StringValue
|
|
191
|
+
The string to check.
|
|
192
|
+
suffix: StringValue
|
|
193
|
+
The suffix to check for.
|
|
194
|
+
|
|
195
|
+
Returns
|
|
196
|
+
-------
|
|
197
|
+
Expression
|
|
198
|
+
An `Expression` that evaluates to `true` if `s` ends with `suffix`.
|
|
199
|
+
|
|
200
|
+
Examples
|
|
201
|
+
--------
|
|
202
|
+
Filter strings that end with a suffix:
|
|
203
|
+
|
|
204
|
+
>>> select(Person.name).where(strings.endswith(Person.last_name, "dottir"))
|
|
205
|
+
"""
|
|
67
206
|
return _ends_with(s, suffix)
|
|
68
207
|
|
|
208
|
+
_len = library.Relation("len", [Field.input("s", String), Field("result", Integer)])
|
|
209
|
+
|
|
210
|
+
@include_in_docs
|
|
69
211
|
def len(s: StringValue) -> Expression:
|
|
70
|
-
"""
|
|
212
|
+
"""
|
|
213
|
+
Get the length of the string `s`.
|
|
214
|
+
|
|
215
|
+
Parameters
|
|
216
|
+
----------
|
|
217
|
+
s: StringValue
|
|
218
|
+
The string to measure.
|
|
219
|
+
|
|
220
|
+
Returns
|
|
221
|
+
-------
|
|
222
|
+
Expression
|
|
223
|
+
An `Expression` representing the length of the string. Returns `Integer`.
|
|
224
|
+
|
|
225
|
+
Examples
|
|
226
|
+
--------
|
|
227
|
+
Get the length of a string:
|
|
228
|
+
|
|
229
|
+
>>> select(Person.name, strings.len(Person.name))
|
|
230
|
+
"""
|
|
71
231
|
return _len(s)
|
|
72
232
|
|
|
233
|
+
_levenshtein = library.Relation("levenshtein", [Field.input("s1", String), Field.input("s2", String), Field("result", Integer)])
|
|
234
|
+
|
|
235
|
+
@include_in_docs
|
|
73
236
|
def levenshtein(s1: StringValue, s2: StringValue) -> Expression:
|
|
74
|
-
"""
|
|
237
|
+
"""
|
|
238
|
+
Compute the Levenshtein distance between two strings.
|
|
239
|
+
|
|
240
|
+
Parameters
|
|
241
|
+
----------
|
|
242
|
+
s1: StringValue
|
|
243
|
+
The first string.
|
|
244
|
+
s2: StringValue
|
|
245
|
+
The second string.
|
|
246
|
+
|
|
247
|
+
Returns
|
|
248
|
+
-------
|
|
249
|
+
Expression
|
|
250
|
+
An `Expression` representing the Levenshtein edit distance. Returns `Integer`.
|
|
251
|
+
|
|
252
|
+
Examples
|
|
253
|
+
--------
|
|
254
|
+
Calculate edit distance between two strings:
|
|
255
|
+
|
|
256
|
+
>>> strings.levenshtein("kitten", "sitting")
|
|
257
|
+
>>> strings.levenshtein(Car.make, "target")
|
|
258
|
+
"""
|
|
75
259
|
return _levenshtein(s1, s2)
|
|
76
260
|
|
|
261
|
+
_like = library.Relation("like", [Field.input("s", String), Field.input("pattern", String)])
|
|
262
|
+
|
|
263
|
+
@include_in_docs
|
|
77
264
|
def like(s: StringValue, pattern: StringValue) -> Expression:
|
|
78
|
-
"""
|
|
265
|
+
"""
|
|
266
|
+
Check whether `s` matches the SQL LIKE pattern `pattern`.
|
|
267
|
+
|
|
268
|
+
Parameters
|
|
269
|
+
----------
|
|
270
|
+
s: StringValue
|
|
271
|
+
The string to match against.
|
|
272
|
+
pattern: StringValue
|
|
273
|
+
The SQL LIKE pattern (`%` for wildcard, `_` for single character).
|
|
274
|
+
|
|
275
|
+
Returns
|
|
276
|
+
-------
|
|
277
|
+
Expression
|
|
278
|
+
An `Expression` that evaluates to `true` if `s` matches the pattern.
|
|
279
|
+
|
|
280
|
+
Examples
|
|
281
|
+
--------
|
|
282
|
+
Match strings using SQL LIKE patterns:
|
|
283
|
+
|
|
284
|
+
>>> select(Brand.name).where(strings.like(Brand.name, r"Mc%"))
|
|
285
|
+
>>> select(Brand.name).where(strings.like(Brand.name, r"%est%"))
|
|
286
|
+
"""
|
|
79
287
|
return _like(s, pattern)
|
|
80
288
|
|
|
289
|
+
_lower = library.Relation("lower", [Field.input("s", String), Field("result", String)])
|
|
290
|
+
|
|
291
|
+
@include_in_docs
|
|
81
292
|
def lower(s: StringValue) -> Expression:
|
|
82
|
-
"""
|
|
293
|
+
"""
|
|
294
|
+
Convert the string `s` to lowercase.
|
|
295
|
+
|
|
296
|
+
Parameters
|
|
297
|
+
----------
|
|
298
|
+
s: StringValue
|
|
299
|
+
The string to convert.
|
|
300
|
+
|
|
301
|
+
Returns
|
|
302
|
+
-------
|
|
303
|
+
Expression
|
|
304
|
+
An `Expression` representing the lowercase version of the string. Returns `String`.
|
|
305
|
+
|
|
306
|
+
Examples
|
|
307
|
+
--------
|
|
308
|
+
Convert a string to lowercase:
|
|
309
|
+
|
|
310
|
+
>>> select(strings.lower(Person.last_name))
|
|
311
|
+
>>> select(City.name).where(strings.lower(City.province) == "ontario")
|
|
312
|
+
"""
|
|
83
313
|
return _lower(s)
|
|
84
314
|
|
|
315
|
+
_upper = library.Relation("upper", [Field.input("s", String), Field("result", String)])
|
|
316
|
+
|
|
317
|
+
@include_in_docs
|
|
318
|
+
def upper(s: StringValue) -> Expression:
|
|
319
|
+
"""
|
|
320
|
+
Convert the string `s` to uppercase.
|
|
321
|
+
|
|
322
|
+
Parameters
|
|
323
|
+
----------
|
|
324
|
+
s: StringValue
|
|
325
|
+
The string to convert.
|
|
326
|
+
|
|
327
|
+
Returns
|
|
328
|
+
-------
|
|
329
|
+
Expression
|
|
330
|
+
An `Expression` representing the uppercase version of the string. Returns `String`.
|
|
331
|
+
|
|
332
|
+
Examples
|
|
333
|
+
--------
|
|
334
|
+
Convert a string to uppercase:
|
|
335
|
+
|
|
336
|
+
>>> select(strings.upper(Person.last_name))
|
|
337
|
+
>>> select(City.name).where(strings.upper(City.province) == "ONTARIO")
|
|
338
|
+
"""
|
|
339
|
+
return _upper(s)
|
|
340
|
+
|
|
341
|
+
_replace = library.Relation("replace", [Field.input("source", String), Field.input("old", String), Field.input("new", String), Field("result", String)])
|
|
342
|
+
|
|
343
|
+
@include_in_docs
|
|
85
344
|
def replace(source: StringValue, old: StringValue, new: StringValue) -> Expression:
|
|
86
|
-
"""
|
|
345
|
+
"""
|
|
346
|
+
Replace occurrences of `old` with `new` in the string `source`.
|
|
347
|
+
|
|
348
|
+
Parameters
|
|
349
|
+
----------
|
|
350
|
+
source: StringValue
|
|
351
|
+
The original string.
|
|
352
|
+
old: StringValue
|
|
353
|
+
The substring to replace.
|
|
354
|
+
new: StringValue
|
|
355
|
+
The replacement substring.
|
|
356
|
+
|
|
357
|
+
Returns
|
|
358
|
+
-------
|
|
359
|
+
Expression
|
|
360
|
+
An `Expression` representing the string with replacements applied. Returns `String`.
|
|
361
|
+
|
|
362
|
+
Examples
|
|
363
|
+
--------
|
|
364
|
+
Replace substrings within a string:
|
|
365
|
+
|
|
366
|
+
>>> strings.replace("My-name", "-", "_")
|
|
367
|
+
>>> strings.replace(Brand.name, "bee", "")
|
|
368
|
+
"""
|
|
87
369
|
return _replace(source, old, new)
|
|
88
370
|
|
|
89
|
-
|
|
90
|
-
""" Check whether `s` starts with `prefix`. """
|
|
91
|
-
return _starts_with(s, prefix)
|
|
371
|
+
_split = library.Relation("split", [Field.input("s", String), Field.input("separator", String), Field("index", Integer), Field("result", String)])
|
|
92
372
|
|
|
373
|
+
@include_in_docs
|
|
93
374
|
def split(s: StringValue, separator: StringValue) -> tuple[Variable, Variable]:
|
|
94
|
-
"""
|
|
375
|
+
"""
|
|
376
|
+
Split the string `s` by `separator`, returning variables holding index and result.
|
|
377
|
+
|
|
378
|
+
Parameters
|
|
379
|
+
----------
|
|
380
|
+
s: StringValue
|
|
381
|
+
The string to split.
|
|
382
|
+
separator: StringValue
|
|
383
|
+
The separator to split by.
|
|
384
|
+
|
|
385
|
+
Returns
|
|
386
|
+
-------
|
|
387
|
+
tuple[Variable, Variable]
|
|
388
|
+
A tuple of `(index, result)` variables representing the split parts. Index is `Integer`, result is `String`.
|
|
389
|
+
|
|
390
|
+
Examples
|
|
391
|
+
--------
|
|
392
|
+
Split a string and get index and result variables:
|
|
393
|
+
|
|
394
|
+
>>> idx, part = strings.split("my_email@mail.test", "@")
|
|
395
|
+
>>> select(idx, part)
|
|
396
|
+
"""
|
|
95
397
|
idx = Integer.ref("index")
|
|
96
398
|
res = String.ref("result")
|
|
97
399
|
exp = _split(s, separator, idx, res)
|
|
98
400
|
return exp[2], exp[3]
|
|
99
401
|
|
|
402
|
+
@include_in_docs
|
|
100
403
|
def split_part(s: StringValue, separator: StringValue, index: IntegerValue) -> Expression:
|
|
101
|
-
"""
|
|
404
|
+
"""
|
|
405
|
+
Get the part of the string `s` at `index` after splitting by `separator`.
|
|
406
|
+
|
|
407
|
+
Parameters
|
|
408
|
+
----------
|
|
409
|
+
s: StringValue
|
|
410
|
+
The string to split.
|
|
411
|
+
separator: StringValue
|
|
412
|
+
The separator to split by.
|
|
413
|
+
index: IntegerValue
|
|
414
|
+
The index of the part to retrieve (0-based).
|
|
415
|
+
|
|
416
|
+
Returns
|
|
417
|
+
-------
|
|
418
|
+
Expression
|
|
419
|
+
An `Expression` representing the string part at the specified index. Returns `String`.
|
|
420
|
+
|
|
421
|
+
Examples
|
|
422
|
+
--------
|
|
423
|
+
Get a specific part of a split string:
|
|
424
|
+
|
|
425
|
+
>>> strings.split_part("my_email@mail.test", "@", 1)
|
|
426
|
+
"""
|
|
102
427
|
return _split(s, separator, index)
|
|
103
428
|
|
|
429
|
+
_strip = library.Relation("strip", [Field.input("s", String), Field("result", String)])
|
|
430
|
+
|
|
431
|
+
@include_in_docs
|
|
104
432
|
def strip(s: StringValue) -> Expression:
|
|
105
|
-
"""
|
|
433
|
+
"""
|
|
434
|
+
Strip whitespace from both ends of the string `s`.
|
|
435
|
+
|
|
436
|
+
Parameters
|
|
437
|
+
----------
|
|
438
|
+
s: StringValue
|
|
439
|
+
The string to strip.
|
|
440
|
+
|
|
441
|
+
Returns
|
|
442
|
+
-------
|
|
443
|
+
Expression
|
|
444
|
+
An `Expression` representing the string with leading and trailing whitespace removed. Returns `String`.
|
|
445
|
+
|
|
446
|
+
Examples
|
|
447
|
+
--------
|
|
448
|
+
Remove whitespace from both ends of a string:
|
|
449
|
+
|
|
450
|
+
>>> select(strings.strip(Person.name))
|
|
451
|
+
>>> select(Text.content).where(strings.strip(Text.content) == "string with spaces")
|
|
452
|
+
"""
|
|
106
453
|
return _strip(s)
|
|
107
454
|
|
|
455
|
+
_substring = library.Relation("substring", [Field.input("s", String), Field.input("start", Integer), Field.input("stop", Integer), Field("result", String)])
|
|
456
|
+
|
|
457
|
+
@include_in_docs
|
|
108
458
|
def substring(s: StringValue, start: IntegerValue, stop: IntegerValue) -> Expression:
|
|
109
|
-
"""
|
|
459
|
+
"""
|
|
460
|
+
Get the substring of `s` from `start` to `stop` (0-based, stop exclusive).
|
|
461
|
+
|
|
462
|
+
Parameters
|
|
463
|
+
----------
|
|
464
|
+
s: StringValue
|
|
465
|
+
The string to extract from.
|
|
466
|
+
start: IntegerValue
|
|
467
|
+
The starting index (0-based, inclusive).
|
|
468
|
+
stop: IntegerValue
|
|
469
|
+
The ending index (0-based, exclusive).
|
|
470
|
+
|
|
471
|
+
Returns
|
|
472
|
+
-------
|
|
473
|
+
Expression
|
|
474
|
+
An `Expression` representing the extracted substring. Returns `String`.
|
|
475
|
+
|
|
476
|
+
Examples
|
|
477
|
+
--------
|
|
478
|
+
Extract a substring from a string:
|
|
479
|
+
|
|
480
|
+
>>> strings.substring(Person.name, 0, 3)
|
|
481
|
+
>>> strings.substring("example", 2, 5)
|
|
482
|
+
"""
|
|
110
483
|
return _substring(s, start, stop)
|
|
111
484
|
|
|
112
|
-
|
|
113
|
-
""" Convert the string `s` to uppercase. """
|
|
114
|
-
return _upper(s)
|
|
485
|
+
_regex_match = library.Relation("regex_match", [Field.input("regex", String), Field.input("value", String)])
|
|
115
486
|
|
|
487
|
+
@include_in_docs
|
|
116
488
|
def regex_match(value: StringValue, regex: StringValue) -> Expression:
|
|
117
|
-
"""
|
|
489
|
+
"""
|
|
490
|
+
Check if the `value` matches the given `regex`.
|
|
491
|
+
|
|
492
|
+
Parameters
|
|
493
|
+
----------
|
|
494
|
+
value: StringValue
|
|
495
|
+
The string value to match against.
|
|
496
|
+
regex: StringValue
|
|
497
|
+
The regular expression pattern.
|
|
498
|
+
|
|
499
|
+
Returns
|
|
500
|
+
-------
|
|
501
|
+
Expression
|
|
502
|
+
An `Expression` that evaluates to `true` if `value` matches the `regex` pattern.
|
|
503
|
+
|
|
504
|
+
Examples
|
|
505
|
+
--------
|
|
506
|
+
Match strings using regular expressions:
|
|
507
|
+
|
|
508
|
+
>>> select(Person.name).where(strings.regex_match(Person.name, r".*ohn.*"))
|
|
509
|
+
>>> select(Person.name).where(not_(strings.regex_match("ohn", Person.name)))
|
|
510
|
+
"""
|
|
118
511
|
return _regex_match(regex, value)
|