|
1 |
| -import { analyzeDocuments } from '../../src'; |
2 | 1 | import Ajv2020 from 'ajv/dist/2020';
|
3 | 2 | import assert from 'assert';
|
4 |
| -import { ObjectId, Int32, Double, EJSON } from 'bson'; |
| 3 | +import { |
| 4 | + Double, |
| 5 | + Int32, |
| 6 | + ObjectId, |
| 7 | + EJSON |
| 8 | +} from 'bson'; |
5 | 9 | import { MongoClient, type Db } from 'mongodb';
|
6 | 10 | import { mochaTestServer } from '@mongodb-js/compass-test-server';
|
7 | 11 |
|
| 12 | +import { allValidBSONTypesWithEdgeCasesDoc } from '../all-bson-types-fixture'; |
| 13 | +import { analyzeDocuments } from '../../src'; |
| 14 | + |
8 | 15 | const bsonDocuments = [{
|
9 | 16 | _id: new ObjectId('67863e82fb817085a6b0ebad'),
|
10 | 17 | title: 'My book',
|
@@ -47,74 +54,156 @@ describe('Documents -> Generate schema -> Validate Documents against the schema'
|
47 | 54 | });
|
48 | 55 | });
|
49 | 56 |
|
50 |
| -describe('Documents -> Generate schema -> Use schema in validation rule in MongoDB -> Validate documents against the schema', function() { |
| 57 | +describe('With a MongoDB Cluster', function() { |
51 | 58 | let client: MongoClient;
|
52 | 59 | let db: Db;
|
53 | 60 | const cluster = mochaTestServer();
|
54 | 61 |
|
55 | 62 | before(async function() {
|
56 |
| - // Create the schema validation rule. |
57 |
| - const analyzedDocuments = await analyzeDocuments(bsonDocuments); |
58 |
| - const schema = await analyzedDocuments.getMongoDBJsonSchema(); |
59 |
| - const validationRule = { |
60 |
| - $jsonSchema: schema |
61 |
| - }; |
62 |
| - |
63 | 63 | // Connect to the mongodb instance.
|
64 | 64 | const connectionString = cluster().connectionString;
|
65 | 65 | client = new MongoClient(connectionString);
|
66 | 66 | await client.connect();
|
67 | 67 | db = client.db('test');
|
68 |
| - |
69 |
| - // Create a collection with the schema validation in Compass. |
70 |
| - await db.createCollection('books', { |
71 |
| - validator: validationRule |
72 |
| - }); |
73 | 68 | });
|
| 69 | + |
74 | 70 | after(async function() {
|
75 | 71 | await client?.close();
|
76 | 72 | });
|
77 | 73 |
|
78 |
| - it('allows inserting valid documents', async function() { |
79 |
| - await db.collection('books').insertMany(bsonDocuments); |
80 |
| - }); |
| 74 | + describe('Documents -> Generate basic schema -> Use schema in validation rule in MongoDB -> Validate documents against the schema', function() { |
| 75 | + before(async function() { |
| 76 | + // Create the schema validation rule. |
| 77 | + const analyzedDocuments = await analyzeDocuments(bsonDocuments); |
| 78 | + const schema = await analyzedDocuments.getMongoDBJsonSchema(); |
| 79 | + const validationRule = { |
| 80 | + $jsonSchema: schema |
| 81 | + }; |
| 82 | + |
| 83 | + // Create a collection with the schema validation. |
| 84 | + await db.createCollection('books', { |
| 85 | + validator: validationRule |
| 86 | + }); |
| 87 | + }); |
| 88 | + |
| 89 | + it('allows inserting valid documents', async function() { |
| 90 | + await db.collection('books').insertMany(bsonDocuments); |
| 91 | + }); |
| 92 | + |
| 93 | + it('prevents inserting invalid documents', async function() { |
| 94 | + const invalidDocs = [{ |
| 95 | + _id: new ObjectId('67863e82fb817085a6b0ebba'), |
| 96 | + title: 'Pineapple 1', |
| 97 | + year: new Int32(1983), |
| 98 | + genres: [ |
| 99 | + 'crimi', |
| 100 | + 'comedy', |
| 101 | + { |
| 102 | + short: 'scifi', |
| 103 | + long: 'science fiction' |
| 104 | + } |
| 105 | + ], |
| 106 | + number: 'an invalid string' |
| 107 | + }, { |
| 108 | + _id: new ObjectId('67863eacfb817085a6b0ebbb'), |
| 109 | + title: 'Pineapple 2', |
| 110 | + year: 'year a string' |
| 111 | + }, { |
| 112 | + _id: new ObjectId('67863eacfb817085a6b0ebbc'), |
| 113 | + title: 123, |
| 114 | + year: new Int32('1999') |
| 115 | + }, { |
| 116 | + _id: new ObjectId('67863eacfb817085a6b0ebbc'), |
| 117 | + title: 'No year' |
| 118 | + }]; |
81 | 119 |
|
82 |
| - it('prevents inserting invalid documents', async function() { |
83 |
| - const invalidDocs = [{ |
84 |
| - _id: new ObjectId('67863e82fb817085a6b0ebba'), |
85 |
| - title: 'Pineapple 1', |
86 |
| - year: new Int32(1983), |
87 |
| - genres: [ |
88 |
| - 'crimi', |
89 |
| - 'comedy', |
90 |
| - { |
91 |
| - short: 'scifi', |
92 |
| - long: 'science fiction' |
| 120 | + for (const doc of invalidDocs) { |
| 121 | + try { |
| 122 | + await db.collection('books').insertOne(doc); |
| 123 | + |
| 124 | + throw new Error('This should not be reached'); |
| 125 | + } catch (e: any) { |
| 126 | + const expectedMessage = 'Document failed validation'; |
| 127 | + assert.ok(e.message.includes(expectedMessage), `Expected error ${e.message} message to include "${expectedMessage}", doc: ${doc._id}`); |
93 | 128 | }
|
94 |
| - ], |
95 |
| - number: 'an invalid string' |
96 |
| - }, { |
97 |
| - _id: new ObjectId('67863eacfb817085a6b0ebbb'), |
98 |
| - title: 'Pineapple 2', |
99 |
| - year: 'year a string' |
100 |
| - }, { |
101 |
| - _id: new ObjectId('67863eacfb817085a6b0ebbc'), |
102 |
| - title: 123, |
103 |
| - year: new Int32('1999') |
104 |
| - }, { |
105 |
| - _id: new ObjectId('67863eacfb817085a6b0ebbc'), |
106 |
| - title: 'No year' |
107 |
| - }]; |
108 |
| - |
109 |
| - for (const doc of invalidDocs) { |
| 129 | + } |
| 130 | + }); |
| 131 | + }); |
| 132 | + |
| 133 | + describe('[All Types] Documents -> Generate basic schema -> Use schema in validation rule in MongoDB -> Validate documents against the schema', function() { |
| 134 | + const allTypesCollection = 'allTypes'; |
| 135 | + |
| 136 | + before(async function() { |
| 137 | + await db.collection(allTypesCollection).insertOne(allValidBSONTypesWithEdgeCasesDoc); |
| 138 | + const docsFromCollection = await db.collection(allTypesCollection).find({}, { promoteValues: false }).toArray(); |
| 139 | + |
| 140 | + // Create the schema validation rule. |
| 141 | + const analyzedDocuments = await analyzeDocuments(docsFromCollection); |
| 142 | + const schema = await analyzedDocuments.getMongoDBJsonSchema(); |
| 143 | + const validationRule = { |
| 144 | + $jsonSchema: schema |
| 145 | + }; |
| 146 | + // Update the collection with the schema validation. |
| 147 | + await db.command({ |
| 148 | + collMod: allTypesCollection, |
| 149 | + validator: validationRule |
| 150 | + }); |
| 151 | + }); |
| 152 | + |
| 153 | + it('allows inserting valid documents (does not error)', async function() { |
| 154 | + const docs = [{ |
| 155 | + ...allValidBSONTypesWithEdgeCasesDoc, |
| 156 | + _id: new ObjectId() |
| 157 | + }, { |
| 158 | + ...allValidBSONTypesWithEdgeCasesDoc, |
| 159 | + _id: new ObjectId() |
| 160 | + }]; |
| 161 | + |
110 | 162 | try {
|
111 |
| - await db.collection('books').insertOne(doc); |
| 163 | + await db.collection(allTypesCollection).insertMany(docs); |
| 164 | + } catch (err) { |
| 165 | + console.error('Error inserting documents', EJSON.stringify(err, undefined, 2)); |
| 166 | + throw err; |
| 167 | + } |
| 168 | + }); |
| 169 | + |
| 170 | + it('prevents inserting invalid documents', async function() { |
| 171 | + const invalidDocs = [{ |
| 172 | + _id: new ObjectId('67863e82fb817085a6b0ebba'), |
| 173 | + title: 'Pineapple 1', |
| 174 | + year: new Int32(1983), |
| 175 | + genres: [ |
| 176 | + 'crimi', |
| 177 | + 'comedy', |
| 178 | + { |
| 179 | + short: 'scifi', |
| 180 | + long: 'science fiction' |
| 181 | + } |
| 182 | + ], |
| 183 | + number: 'an invalid string' |
| 184 | + }, { |
| 185 | + _id: new ObjectId('67863eacfb817085a6b0ebbb'), |
| 186 | + title: 'Pineapple 2', |
| 187 | + year: 'year a string' |
| 188 | + }, { |
| 189 | + _id: new ObjectId('67863eacfb817085a6b0ebbc'), |
| 190 | + title: 123, |
| 191 | + year: new Int32('1999') |
| 192 | + }, { |
| 193 | + _id: new ObjectId('67863eacfb817085a6b0ebbc'), |
| 194 | + title: 'No year' |
| 195 | + }]; |
| 196 | + |
| 197 | + for (const doc of invalidDocs) { |
| 198 | + try { |
| 199 | + await db.collection(allTypesCollection).insertOne(doc); |
112 | 200 |
|
113 |
| - throw new Error('This should not be reached'); |
114 |
| - } catch (e: any) { |
115 |
| - const expectedMessage = 'Document failed validation'; |
116 |
| - assert.ok(e.message.includes(expectedMessage), `Expected error ${e.message} message to include "${expectedMessage}", doc: ${doc._id}`); |
| 201 | + throw new Error('This should not be reached'); |
| 202 | + } catch (e: any) { |
| 203 | + const expectedMessage = 'Document failed validation'; |
| 204 | + assert.ok(e.message.includes(expectedMessage), `Expected error ${e.message} message to include "${expectedMessage}", doc: ${doc._id}`); |
| 205 | + } |
117 | 206 | }
|
118 |
| - } |
| 207 | + }); |
119 | 208 | });
|
120 | 209 | });
|
0 commit comments