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
|
// Aggregation $substrBytes tests.
t = db.jstests_aggregation_substr;
t.drop();
t.save({});
function assertSubstring(expected, str, offset, len) {
assert.eq(expected,
t.aggregate({$project: {a: {$substrBytes: [str, offset, len]}}}).toArray()[0].a);
}
function assertArgsException(args) {
assert.commandFailed(t.runCommand('aggregate', {pipeline: [{$substrBytes: args}]}));
}
function assertException(str, offset, len) {
assertArgsException([str, offset, len]);
}
// Wrong number of arguments.
assertArgsException([]);
assertArgsException(['foo']);
assertArgsException(['foo', 1]);
assertArgsException(['foo', 1, 1, 1]);
// Basic offset / length checks.
assertSubstring('abcd', 'abcd', 0, 4);
assertSubstring('abcd', 'abcd', 0, 5);
assertSubstring('', 'abcd', -1 /* unsigned */, 4);
assertSubstring('a', 'abcd', 0, 1);
assertSubstring('ab', 'abcd', 0, 2);
assertSubstring('b', 'abcd', 1, 1);
assertSubstring('d', 'abcd', 3, 1);
assertSubstring('', 'abcd', 4, 1);
assertSubstring('', 'abcd', 3, 0);
assertSubstring('cd', 'abcd', 2, -1 /* unsigned */);
// See server6186.js for additional offset / length checks.
// Additional numeric types for offset / length.
assertSubstring('bc', 'abcd', 1, 2);
assertSubstring('bc', 'abcd', 1.0, 2.0);
assertSubstring('bc', 'abcd', NumberInt(1), NumberInt(2));
assertSubstring('bc', 'abcd', NumberLong(1), NumberLong(2));
assertSubstring('bc', 'abcd', NumberInt(1), NumberLong(2));
assertSubstring('bc', 'abcd', NumberLong(1), NumberInt(2));
// Integer component is used.
assertSubstring('bc', 'abcd', 1.2, 2.2);
assertSubstring('bc', 'abcd', 1.9, 2.9);
// Non numeric types for offset / length.
assertException('abcd', false, 2);
assertException('abcd', 1, true);
assertException('abcd', 'q', 2);
assertException('abcd', 1, 'r');
assertException('abcd', null, 3);
assertException('abcd', 1, undefined);
// String coercion.
assertSubstring('123', 123, 0, 3);
assertSubstring('2', 123, 1, 1);
assertSubstring('1970', new Date(0), 0, 4);
assertSubstring('', null, 0, 4);
assertException(/abc/, 0, 4);
// Field path like string.
assertSubstring('$a', 'a$a', 1, 2);
// Multi byte utf-8.
assertSubstring('\u0080', '\u0080', 0, 2);
assertException('\u0080', 0, 1);
assertException('\u0080', 1, 1);
assertSubstring('\u0080', '\u0080\u20ac', 0, 2);
assertSubstring('\u20ac', '\u0080\u20ac', 2, 3);
assertException('\u0080\u20ac', 1, 3);
assertException('\u0080\u20ac', 1, 4);
assertException('\u0080\u20ac', 0, 3);
assertSubstring('\u0044\u20ac', '\u0080\u0044\u20ac', 2, 4);
assertSubstring('\u0044', '\u0080\u0044\u20ac', 2, 1);
// The four byte utf-8 character 𝌆 (have to represent in surrogate halves).
assertSubstring('\uD834\uDF06', '\uD834\uDF06', 0, 4);
assertException('\uD834\uDF06', '\uD834\uDF06', 1, 4);
assertException('\uD834\uDF06', '\uD834\uDF06', 0, 3);
// Operands from document.
t.drop();
t.save({x: 'a', y: 'abc', z: 'abcde', a: 0, b: 1, c: 2, d: 3, e: 4, f: 5});
assertSubstring('a', '$x', '$a', '$b');
assertSubstring('a', '$x', '$a', '$f');
assertSubstring('b', '$y', '$b', '$b');
assertSubstring('b', '$z', '$b', '$b');
assertSubstring('bcd', '$z', '$b', '$d');
assertSubstring('cde', '$z', '$c', '$f');
assertSubstring('c', '$y', '$c', '$f');
// Computed operands.
assertSubstring('cde', '$z', {$add: ['$b', '$b']}, {$add: ['$c', '$d']});
assertSubstring('cde', '$z', {$add: ['$b', 1]}, {$add: [2, '$d']});
// Nested.
assert.eq(
'e',
t.aggregate({
$project: {
a: {
$substrBytes: [
{
$substrBytes:
[{$substrBytes: [{$substrBytes: ['abcdefghij', 1, 6]}, 2, 5]}, 0, 3]
},
1,
1
]
}
}
})
.toArray()[0]
.a);
|