-
Notifications
You must be signed in to change notification settings - Fork 365
/
text.dart
224 lines (191 loc) · 6.7 KB
/
text.dart
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
part of '../query_builder.dart';
/// Defines methods that operate on a column storing [String] values.
extension StringExpressionOperators on Expression<String?> {
/// Whether this column matches the given pattern. For details on what patters
/// are valid and how they are interpreted, check out
/// [this tutorial](http://www.sqlitetutorial.net/sqlite-like/).
Expression<bool?> like(String regex) {
return _LikeOperator(this, Variable.withString(regex));
}
/// Matches this string against the regular expression in [regex].
///
/// The [multiLine], [caseSensitive], [unicode] and [dotAll] parameters
/// correspond to the parameters on [RegExp].
///
/// Note that this function is only available when using a `NativeDatabase`.
/// If you need to support the web or `moor_flutter`, consider using [like]
/// instead.
Expression<bool?> regexp(
String regex, {
bool multiLine = false,
bool caseSensitive = true,
bool unicode = false,
bool dotAll = false,
}) {
// We have a special regexp sql function that takes a third parameter
// to encode flags. If the least significant bit is set, multiLine is
// enabled. The next three bits enable case INSENSITIVITY (it's sensitive
// by default), unicode and dotAll.
var flags = 0;
if (multiLine) {
flags |= 1;
}
if (!caseSensitive) {
flags |= 2;
}
if (unicode) {
flags |= 4;
}
if (dotAll) {
flags |= 8;
}
if (flags != 0) {
return FunctionCallExpression<bool>(
'regexp_moor_ffi',
[
Variable.withString(regex),
this,
Variable.withInt(flags),
],
);
}
// No special flags enabled, use the regular REGEXP operator
return _LikeOperator(this, Variable.withString(regex), operator: 'REGEXP');
}
/// Whether this expression contains [substring].
///
/// Note that this is case-insensitive for the English alphabet only.
///
/// This is equivalent to calling [like] with `%<substring>%`.
Expression<bool?> contains(String substring) {
return like('%$substring%');
}
/// Uses the given [collate] sequence when comparing this column to other
/// values.
Expression<String> collate(Collate collate) {
return _CollateOperator(this, collate);
}
/// Performs a string concatenation in sql by appending [other] to `this`.
Expression<String> operator +(Expression<String?> other) {
return _BaseInfixOperator(this, '||', other,
precedence: Precedence.stringConcatenation);
}
/// Calls the sqlite function `UPPER` on `this` string. Please note that, in
/// most sqlite installations, this only affects ascii chars.
///
/// See also:
/// - https://www.w3resource.com/sqlite/core-functions-upper.php
Expression<String> upper() {
return FunctionCallExpression('UPPER', [this]);
}
/// Calls the sqlite function `LOWER` on `this` string. Please note that, in
/// most sqlite installations, this only affects ascii chars.
///
/// See also:
/// - https://www.w3resource.com/sqlite/core-functions-lower.php
Expression<String> lower() {
return FunctionCallExpression('LOWER', [this]);
}
/// Calls the sqlite function `LENGTH` on `this` string, which counts the
/// number of characters in this string. Note that, in most sqlite
/// installations, [length] may not support all unicode rules.
///
/// See also:
/// - https://www.w3resource.com/sqlite/core-functions-length.php
Expression<int?> get length {
return FunctionCallExpression('LENGTH', [this]);
}
/// Removes spaces from both ends of this string.
Expression<String?> trim() {
return FunctionCallExpression('TRIM', [this]);
}
/// Removes spaces from the beginning of this string.
Expression<String?> trimLeft() {
return FunctionCallExpression('LTRIM', [this]);
}
/// Removes spaces from the end of this string.
Expression<String?> trimRight() {
return FunctionCallExpression('RTRIM', [this]);
}
}
/// A `text LIKE pattern` expression that will be true if the first expression
/// matches the pattern given by the second expression.
class _LikeOperator extends Expression<bool?> {
/// The target expression that will be tested
final Expression<String?> target;
/// The regex-like expression to test the [target] against.
final Expression<String?> regex;
/// The operator to use when matching. Defaults to `LIKE`.
final String operator;
@override
final Precedence precedence = Precedence.comparisonEq;
/// Perform a like operator with the target and the regex.
_LikeOperator(this.target, this.regex, {this.operator = 'LIKE'});
@override
void writeInto(GenerationContext context) {
writeInner(context, target);
context.writeWhitespace();
context.buffer.write(operator);
context.writeWhitespace();
writeInner(context, regex);
}
@override
int get hashCode => Object.hash(target, regex, operator);
@override
bool operator ==(Object other) {
return other is _LikeOperator &&
other.target == target &&
other.regex == regex &&
other.operator == operator;
}
}
/// Builtin collating functions from sqlite.
///
/// See also:
/// - https://www.sqlite.org/datatype3.html#collation
enum Collate {
/// Instruct sqlite to compare string data using memcmp(), regardless of text
/// encoding.
binary,
/// The same as [Collate.binary], except the 26 upper case characters of ASCII
/// are folded to their lower case equivalents before the comparison is
/// performed. Note that only ASCII characters are case folded. SQLite does
/// not attempt to do full UTF case folding due to the size of the tables
/// required.
noCase,
/// The same as [Collate.binary], except that trailing space characters are
/// ignored.
rTrim,
}
/// A `text COLLATE collate` expression in sqlite.
class _CollateOperator extends Expression<String> {
/// The expression on which the collate function will be run
final Expression inner;
/// The [Collate] to use.
final Collate collate;
@override
final Precedence precedence = Precedence.postfix;
/// Constructs a collate expression on the [inner] expression and the
/// [Collate].
_CollateOperator(this.inner, this.collate);
@override
void writeInto(GenerationContext context) {
writeInner(context, inner);
context.buffer
..write(' COLLATE ')
..write(_operatorNames[collate]);
}
@override
int get hashCode => Object.hash(inner, collate);
@override
bool operator ==(Object other) {
return other is _CollateOperator &&
other.inner == inner &&
other.collate == collate;
}
static const Map<Collate, String> _operatorNames = {
Collate.binary: 'BINARY',
Collate.noCase: 'NOCASE',
Collate.rTrim: 'RTRIM',
};
}