summaryrefslogtreecommitdiff
path: root/jstests/aggregation/sources/unionWith/unionWith_collation.js
blob: 1e0ee6c771f3bdf4639fac34d6e195f0e3b167a1 (plain)
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
/**
 * Tests that $unionWith respects the user-specified collation or the inherited local collation
 * when performing comparisons on a foreign collection/view with a different default collation.
 *
 * We are explicitly creating collections with collation as part of this test. So we will receive
 * 'NamespaceExists' error if we allow implicit creation.
 * @tags: [
 *   assumes_no_implicit_collection_creation_after_drop,
 * ]
 */
(function() {

"use strict";

const testDB = db.getSiblingDB(jsTestName());
const noCollationColl = testDB.no_collation;
const caseInsensitiveColl = testDB.case_insensitive;

caseInsensitiveColl.drop();
noCollationColl.drop();

const caseInsensitiveCollation = {
    locale: "en_US",
    strength: 1
};
const simpleCollation = {
    locale: "simple"
};

// Create a case-sensitive/simple collection and a case-insensitive collection.
assert.commandWorked(testDB.createCollection(noCollationColl.getName()));
assert.commandWorked(
    testDB.createCollection(caseInsensitiveColl.getName(), {collation: caseInsensitiveCollation}));

assert.commandWorked(noCollationColl.insert([
    {_id: 0, val: "a"},
    {_id: 1, val: "b", caseSensitiveColl: true},
    {_id: 2, val: "B", caseSensitiveColl: true},
    {_id: 3, val: "c"}
]));
assert.commandWorked(caseInsensitiveColl.insert([
    {_id: 0, val: "a"},
    {_id: 1, val: "B", caseSensitiveColl: false},
    {_id: 2, val: "b", caseSensitiveColl: false},
    {_id: 3, val: "c"}
]));

const unionWith = (foreignCollName, values) => {
    return [
        {$match: {val: {$in: values}}},
        {$unionWith: {coll: foreignCollName, pipeline: [{$match: {val: {$in: values}}}]}},
        {
            $sort: {"val": 1, caseSensitiveColl: 1, _id: 1},
        },
        {$project: {_id: 0}}
    ];
};

// Verify that a $unionWith whose local collection has no default collation uses the simple
// collation for comparisons on a foreign collection with a non-simple default collation.
let results = noCollationColl.aggregate(unionWith(caseInsensitiveColl.getName(), ["B"])).toArray();
assert.docEq(results, [{val: "B", caseSensitiveColl: false}, {val: "B", caseSensitiveColl: true}]);
// Verify that a $unionWith whose local collection has no default collation but which is running in
// a pipeline with a non-simple user-specified collation uses the latter for comparisons on the
// foreign collection.
results = noCollationColl
              .aggregate(unionWith(caseInsensitiveColl.getName(), ["B"]),
                         {collation: caseInsensitiveCollation})
              .toArray();
assert.docEq(results, [
    {val: "B", caseSensitiveColl: false},  // Case insensitive match on local collection.
    {val: "b", caseSensitiveColl: false},
    {val: "b", caseSensitiveColl: true},
    {val: "B", caseSensitiveColl: true}  // Case insensitive match on foreign collection.
]);

// Verify that a $unionWith whose local collection has a non-simple collation uses the latter for
// comparisons on a foreign collection with no default collation.
results = caseInsensitiveColl.aggregate(unionWith(noCollationColl.getName(), ["B"])).toArray();
assert.docEq(results, [
    {val: "B", caseSensitiveColl: false},  // Case insensitive match on local collection.
    {val: "b", caseSensitiveColl: false},
    {val: "b", caseSensitiveColl: true},
    {val: "B", caseSensitiveColl: true}  // Case insensitive match on foreign collection.
]);

// Verify that a $unionWith whose local collection has a non-simple collation but which is running
// in a pipeline with a user-specified simple collation uses the latter for comparisons on the
// foreign collection.
results = caseInsensitiveColl
              .aggregate(unionWith(noCollationColl.getName(), ["B"]), {collation: simpleCollation})
              .toArray();
assert.docEq(results, [{val: "B", caseSensitiveColl: false}, {val: "B", caseSensitiveColl: true}]);

// Create a case-sensitive/simple view and a case-insensitive view.
testDB.noCollationView.drop();
testDB.caseInsensitiveView.drop();
assert.commandWorked(testDB.runCommand({
    create: "noCollationView",
    viewOn: noCollationColl.getName(),
    pipeline: [{$project: {val: 1, caseSensitiveView: '$caseSensitiveColl'}}]
}));
assert.commandWorked(testDB.runCommand({
    create: "caseInsensitiveView",
    viewOn: caseInsensitiveColl.getName(),
    pipeline: [{$project: {val: 1, caseSensitiveView: '$caseSensitiveColl'}}],
    collation: caseInsensitiveCollation
}));

// Verify that the command succeeds if both the pipeline and the $unionWith'd view uses a simple
// collation.
results =
    caseInsensitiveColl.aggregate(unionWith("noCollationView", ["B"]), {collation: simpleCollation})
        .toArray();
assert.docEq(results, [{val: "B", caseSensitiveView: true}, {val: "B", caseSensitiveColl: false}]);

// Verify that the command fails if the collation of the pipeline doesn't match the collation of the
// view.
assert.commandFailedWithCode(noCollationColl.runCommand({
    aggregate: noCollationColl.getName(),
    pipeline: unionWith("caseInsensitiveView", ["B"]),
    cursor: {}
}),
                             ErrorCodes.OptionNotSupportedOnView);
assert.commandFailedWithCode(noCollationColl.runCommand({
    aggregate: noCollationColl.getName(),
    pipeline: unionWith("caseInsensitiveView", ["B"]),
    collation: simpleCollation,
    cursor: {}
}),
                             ErrorCodes.OptionNotSupportedOnView);

// Verify that the command succeeds if both the pipeline and the $unionWith'd view uses a
// case-insensitive collation.
results = caseInsensitiveColl.aggregate(unionWith("caseInsensitiveView", ["B"])).toArray();
assert.docEq(results, [
    {val: "B", caseSensitiveView: false},
    {val: "b", caseSensitiveView: false},
    {val: "B", caseSensitiveColl: false},
    {val: "b", caseSensitiveColl: false}
]);
})();