Skip to content

Commit 2b06fc0

Browse files
small refactor to aid testing
1 parent ebe3d06 commit 2b06fc0

File tree

3 files changed

+71
-80
lines changed

3 files changed

+71
-80
lines changed

lib/drivers/node-mongodb-native/connection.js

Lines changed: 14 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ const pkg = require('../../../package.json');
1212
const processConnectionOptions = require('../../helpers/processConnectionOptions');
1313
const setTimeout = require('../../helpers/timers').setTimeout;
1414
const utils = require('../../utils');
15-
const { inferBSONType } = require('../../encryption_utils');
1615

1716
/**
1817
* A [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) connection implementation.
@@ -305,8 +304,7 @@ NativeConnection.prototype.createClient = async function createClient(uri, optio
305304
};
306305
}
307306

308-
309-
const { schemaMap, encryptedFieldsMap } = this._buildEncryptionSchemas(options);
307+
const { schemaMap, encryptedFieldsMap } = this._buildEncryptionSchemas();
310308

311309
if (Object.keys(schemaMap).length > 0) {
312310
options.autoEncryption.schemaMap = schemaMap;
@@ -349,91 +347,28 @@ NativeConnection.prototype.createClient = async function createClient(uri, optio
349347
*/
350348
NativeConnection.prototype._buildEncryptionSchemas = function() {
351349
const schemaMap = Object.values(this.models).filter(model => model.schema.encryptionType() === 'csfle').reduce(
352-
schemaMapReducer.bind(this),
350+
(schemaMap, model) => {
351+
const { schema, collection: { collectionName } } = model;
352+
const namespace = `${this.$dbName}.${collectionName}`;
353+
schemaMap[namespace] = schema._buildSchemaMap();
354+
return schemaMap;
355+
},
353356
{}
354357
);
358+
355359
const encryptedFieldsMap = Object.values(this.models).filter(model => model.schema.encryptionType() === 'qe').reduce(
356-
encryptedFieldsMapReducer.bind(this),
360+
(encryptedFieldsMap, model) => {
361+
const { schema, collection: { collectionName } } = model;
362+
const namespace = `${this.$dbName}.${collectionName}`;
363+
encryptedFieldsMap[namespace] = schema._buildEncryptedFields();
364+
return encryptedFieldsMap;
365+
},
357366
{}
358367
);
359368

360369
return {
361370
schemaMap, encryptedFieldsMap
362371
};
363-
364-
/**
365-
* `schemaMap`s are JSON schemas, which use the following structure to represent objects:
366-
* { field: { bsonType: 'object', properties: { ... } } }
367-
*
368-
* for example, a schema that looks like this `{ a: { b: int32 } }` would be encoded as
369-
* `{ a: { bsonType: 'object', properties: { b: < encryption configuration > } } }`
370-
*
371-
* This function takes an array of path segments, an output object (that gets mutated) and
372-
* a value to associated with the full path, and constructs a valid CSFLE JSON schema path for
373-
* the object. This works for deeply nested properties as well.
374-
*
375-
* @param {string[]} path array of path components
376-
* @param {object} object the object in which to build a JSON schema of `path`'s properties
377-
* @param {object} value the value to associate with the path in object
378-
*/
379-
function buildNestedPath(path, object, value) {
380-
let i = 0, component = path[i];
381-
for (; i < path.length - 1; ++i, component = path[i]) {
382-
object[component] = object[component] == null ? {
383-
bsonType: 'object',
384-
properties: {}
385-
} : object[component];
386-
object = object[component].properties;
387-
}
388-
object[component] = value;
389-
}
390-
391-
/**
392-
* @param {object} schemaMap the accumulation schemaMap
393-
* @param {Model} the model
394-
* @returns
395-
*/
396-
function schemaMapReducer(schemaMap, model) {
397-
const { schema, collection: { collectionName } } = model;
398-
const namespace = `${this.$dbName}.${collectionName}`;
399-
400-
function schemaMapPropertyReducer(accum, [path, propertyConfig]) {
401-
const bsonType = inferBSONType(schema, path);
402-
const pathComponents = path.split('.');
403-
const configuration = { encrypt: { ...propertyConfig, bsonType } };
404-
buildNestedPath(pathComponents, accum, configuration);
405-
return accum;
406-
}
407-
const properties = Object.entries(schema.encryptedFields).reduce(
408-
schemaMapPropertyReducer,
409-
{});
410-
411-
schemaMap[namespace] = {
412-
bsonType: 'object',
413-
properties
414-
};
415-
return schemaMap;
416-
}
417-
418-
/**
419-
*
420-
* @param {object} encryptedFieldsMap the accumulation encryptedFieldsMap
421-
* @param {Model} the model
422-
* @returns
423-
*/
424-
function encryptedFieldsMapReducer(encryptedFieldsMap, { schema, collection: { collectionName } }) {
425-
const namespace = `${this.$dbName}.${collectionName}`;
426-
const fields = Object.entries(schema.encryptedFields).map(
427-
([path, config]) => {
428-
const bsonType = inferBSONType(schema, path);
429-
// { path, bsonType, keyId, queries? }
430-
return { path, bsonType, ...config };
431-
});
432-
433-
encryptedFieldsMap[namespace] = { fields };
434-
435-
return encryptedFieldsMap;
436-
}
437372
};
438373

439374
/*!

lib/schema.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,63 @@ Schema.prototype._hasEncryptedFields = function _hasEncryptedFields() {
917917
return Object.keys(this.encryptedFields).length > 0;
918918
};
919919

920+
Schema.prototype._buildEncryptedFields = function() {
921+
const fields = Object.entries(this.encryptedFields).map(
922+
([path, config]) => {
923+
const bsonType = inferBSONType(this, path);
924+
// { path, bsonType, keyId, queries? }
925+
return { path, bsonType, ...config };
926+
});
927+
928+
return { fields };
929+
};
930+
931+
Schema.prototype._buildSchemaMap = function() {
932+
/**
933+
* `schemaMap`s are JSON schemas, which use the following structure to represent objects:
934+
* { field: { bsonType: 'object', properties: { ... } } }
935+
*
936+
* for example, a schema that looks like this `{ a: { b: int32 } }` would be encoded as
937+
* `{ a: { bsonType: 'object', properties: { b: < encryption configuration > } } }`
938+
*
939+
* This function takes an array of path segments, an output object (that gets mutated) and
940+
* a value to associated with the full path, and constructs a valid CSFLE JSON schema path for
941+
* the object. This works for deeply nested properties as well.
942+
*
943+
* @param {string[]} path array of path components
944+
* @param {object} object the object in which to build a JSON schema of `path`'s properties
945+
* @param {object} value the value to associate with the path in object
946+
*/
947+
function buildNestedPath(path, object, value) {
948+
let i = 0, component = path[i];
949+
for (; i < path.length - 1; ++i, component = path[i]) {
950+
object[component] = object[component] == null ? {
951+
bsonType: 'object',
952+
properties: {}
953+
} : object[component];
954+
object = object[component].properties;
955+
}
956+
object[component] = value;
957+
}
958+
959+
const schemaMapPropertyReducer = (accum, [path, propertyConfig]) => {
960+
const bsonType = inferBSONType(this, path);
961+
const pathComponents = path.split('.');
962+
const configuration = { encrypt: { ...propertyConfig, bsonType } };
963+
buildNestedPath(pathComponents, accum, configuration);
964+
return accum;
965+
};
966+
967+
const properties = Object.entries(this.encryptedFields).reduce(
968+
schemaMapPropertyReducer,
969+
{});
970+
971+
return {
972+
bsonType: 'object',
973+
properties
974+
};
975+
};
976+
920977
/**
921978
* Add an alias for `path`. This means getting or setting the `alias`
922979
* is equivalent to getting or setting the `path`.

test/encryption/encryption.test.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ describe('ci', () => {
8080
assert.ok(doc.field.equals(input));
8181
} else {
8282
assert.deepEqual(doc.field, expected ?? input);
83-
8483
}
8584
}
8685

0 commit comments

Comments
 (0)