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.
Files changed (118) hide show
  1. relationalai/config/config.py +47 -21
  2. relationalai/config/connections/__init__.py +5 -2
  3. relationalai/config/connections/duckdb.py +2 -2
  4. relationalai/config/connections/local.py +31 -0
  5. relationalai/config/connections/snowflake.py +0 -1
  6. relationalai/config/external/raiconfig_converter.py +235 -0
  7. relationalai/config/external/raiconfig_models.py +202 -0
  8. relationalai/config/external/utils.py +31 -0
  9. relationalai/config/shims.py +1 -0
  10. relationalai/semantics/__init__.py +10 -8
  11. relationalai/semantics/backends/sql/sql_compiler.py +1 -4
  12. relationalai/semantics/experimental/__init__.py +0 -0
  13. relationalai/semantics/experimental/builder.py +295 -0
  14. relationalai/semantics/experimental/builtins.py +154 -0
  15. relationalai/semantics/frontend/base.py +67 -42
  16. relationalai/semantics/frontend/core.py +34 -6
  17. relationalai/semantics/frontend/front_compiler.py +209 -37
  18. relationalai/semantics/frontend/pprint.py +6 -2
  19. relationalai/semantics/metamodel/__init__.py +7 -0
  20. relationalai/semantics/metamodel/metamodel.py +2 -0
  21. relationalai/semantics/metamodel/metamodel_analyzer.py +58 -16
  22. relationalai/semantics/metamodel/pprint.py +6 -1
  23. relationalai/semantics/metamodel/rewriter.py +11 -7
  24. relationalai/semantics/metamodel/typer.py +116 -41
  25. relationalai/semantics/reasoners/__init__.py +11 -0
  26. relationalai/semantics/reasoners/graph/__init__.py +35 -0
  27. relationalai/semantics/reasoners/graph/core.py +9028 -0
  28. relationalai/semantics/std/__init__.py +30 -10
  29. relationalai/semantics/std/aggregates.py +641 -12
  30. relationalai/semantics/std/common.py +146 -13
  31. relationalai/semantics/std/constraints.py +71 -1
  32. relationalai/semantics/std/datetime.py +904 -21
  33. relationalai/semantics/std/decimals.py +143 -2
  34. relationalai/semantics/std/floats.py +57 -4
  35. relationalai/semantics/std/integers.py +98 -4
  36. relationalai/semantics/std/math.py +857 -35
  37. relationalai/semantics/std/numbers.py +216 -20
  38. relationalai/semantics/std/re.py +213 -5
  39. relationalai/semantics/std/strings.py +437 -44
  40. relationalai/shims/executor.py +60 -52
  41. relationalai/shims/fixtures.py +85 -0
  42. relationalai/shims/helpers.py +26 -2
  43. relationalai/shims/hoister.py +28 -9
  44. relationalai/shims/mm2v0.py +204 -173
  45. relationalai/tools/cli/cli.py +192 -10
  46. relationalai/tools/cli/components/progress_reader.py +1 -1
  47. relationalai/tools/cli/docs.py +394 -0
  48. relationalai/tools/debugger.py +11 -4
  49. relationalai/tools/qb_debugger.py +435 -0
  50. relationalai/tools/typer_debugger.py +1 -2
  51. relationalai/util/dataclasses.py +3 -5
  52. relationalai/util/docutils.py +1 -2
  53. relationalai/util/error.py +2 -5
  54. relationalai/util/python.py +23 -0
  55. relationalai/util/runtime.py +1 -2
  56. relationalai/util/schema.py +2 -4
  57. relationalai/util/structures.py +4 -2
  58. relationalai/util/tracing.py +8 -2
  59. {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/METADATA +8 -5
  60. {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/RECORD +118 -95
  61. {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/WHEEL +1 -1
  62. v0/relationalai/__init__.py +1 -1
  63. v0/relationalai/clients/client.py +52 -18
  64. v0/relationalai/clients/exec_txn_poller.py +122 -0
  65. v0/relationalai/clients/local.py +23 -8
  66. v0/relationalai/clients/resources/azure/azure.py +36 -11
  67. v0/relationalai/clients/resources/snowflake/__init__.py +4 -4
  68. v0/relationalai/clients/resources/snowflake/cli_resources.py +12 -1
  69. v0/relationalai/clients/resources/snowflake/direct_access_resources.py +124 -100
  70. v0/relationalai/clients/resources/snowflake/engine_service.py +381 -0
  71. v0/relationalai/clients/resources/snowflake/engine_state_handlers.py +35 -29
  72. v0/relationalai/clients/resources/snowflake/error_handlers.py +43 -2
  73. v0/relationalai/clients/resources/snowflake/snowflake.py +277 -179
  74. v0/relationalai/clients/resources/snowflake/use_index_poller.py +8 -0
  75. v0/relationalai/clients/types.py +5 -0
  76. v0/relationalai/errors.py +19 -1
  77. v0/relationalai/semantics/lqp/algorithms.py +173 -0
  78. v0/relationalai/semantics/lqp/builtins.py +199 -2
  79. v0/relationalai/semantics/lqp/executor.py +68 -37
  80. v0/relationalai/semantics/lqp/ir.py +28 -2
  81. v0/relationalai/semantics/lqp/model2lqp.py +215 -45
  82. v0/relationalai/semantics/lqp/passes.py +13 -658
  83. v0/relationalai/semantics/lqp/rewrite/__init__.py +12 -0
  84. v0/relationalai/semantics/lqp/rewrite/algorithm.py +385 -0
  85. v0/relationalai/semantics/lqp/rewrite/constants_to_vars.py +70 -0
  86. v0/relationalai/semantics/lqp/rewrite/deduplicate_vars.py +104 -0
  87. v0/relationalai/semantics/lqp/rewrite/eliminate_data.py +108 -0
  88. v0/relationalai/semantics/lqp/rewrite/extract_keys.py +25 -3
  89. v0/relationalai/semantics/lqp/rewrite/period_math.py +77 -0
  90. v0/relationalai/semantics/lqp/rewrite/quantify_vars.py +65 -31
  91. v0/relationalai/semantics/lqp/rewrite/unify_definitions.py +317 -0
  92. v0/relationalai/semantics/lqp/utils.py +11 -1
  93. v0/relationalai/semantics/lqp/validators.py +14 -1
  94. v0/relationalai/semantics/metamodel/builtins.py +2 -1
  95. v0/relationalai/semantics/metamodel/compiler.py +2 -1
  96. v0/relationalai/semantics/metamodel/dependency.py +12 -3
  97. v0/relationalai/semantics/metamodel/executor.py +11 -1
  98. v0/relationalai/semantics/metamodel/factory.py +2 -2
  99. v0/relationalai/semantics/metamodel/helpers.py +7 -0
  100. v0/relationalai/semantics/metamodel/ir.py +3 -2
  101. v0/relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +30 -20
  102. v0/relationalai/semantics/metamodel/rewrite/flatten.py +50 -13
  103. v0/relationalai/semantics/metamodel/rewrite/format_outputs.py +9 -3
  104. v0/relationalai/semantics/metamodel/typer/checker.py +6 -4
  105. v0/relationalai/semantics/metamodel/typer/typer.py +4 -3
  106. v0/relationalai/semantics/metamodel/visitor.py +4 -3
  107. v0/relationalai/semantics/reasoners/optimization/solvers_dev.py +1 -1
  108. v0/relationalai/semantics/reasoners/optimization/solvers_pb.py +336 -86
  109. v0/relationalai/semantics/rel/compiler.py +2 -1
  110. v0/relationalai/semantics/rel/executor.py +3 -2
  111. v0/relationalai/semantics/tests/lqp/__init__.py +0 -0
  112. v0/relationalai/semantics/tests/lqp/algorithms.py +345 -0
  113. v0/relationalai/tools/cli.py +339 -186
  114. v0/relationalai/tools/cli_controls.py +216 -67
  115. v0/relationalai/tools/cli_helpers.py +410 -6
  116. v0/relationalai/util/format.py +5 -2
  117. {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/entry_points.txt +0 -0
  118. {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, _function_not_implemented
7
- from ..frontend.base import Aggregate, Library, Expression, Field, TupleVariable, Variable
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
- from .aggregates import string_join
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
- # Relationships
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
- # split_part = f.relation("split_part", [f.input_field("a", types.String), f.input_field("b", types.String), f.field("c", types.Int64), f.field("d", types.String)])
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
- # Operations
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
- def string(s: StringValue|float|PyDecimal) -> Expression:
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
- """ Concatenate multiple strings together. """
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
- """ Check whether `substr` is contained within `s`. """
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
- """ Check whether `s` ends with `suffix`. """
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
- """ Get the length of the string `s`. """
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
- """ Compute the Levenshtein distance between two strings. """
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
- """ Check whether `s` matches the SQL LIKE pattern `pattern`. """
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
- """ Convert the string `s` to lowercase. """
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
- """ Replace occurrences of `old` with `new` in the string `source`. """
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
- def startswith(s: StringValue, prefix: StringValue) -> Expression:
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
- """ Split the string `s` by `separator`, returning variables holding index and result. """
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
- """ Get the part of the string `s` at `index` after splitting by `separator`. """
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
- """ Strip whitespace from both ends of the string `s`. """
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
- """ Get the substring of `s` from `start` to `stop` (0-based, stop exclusive). """
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
- def upper(s: StringValue) -> Expression:
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
- """ Check if the `value` matches the given `regex`. """
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)