Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(schema): add alias() method that makes it easier to define multiple aliases for a given path #12491

Merged
merged 8 commits into from
Oct 5, 2022
68 changes: 57 additions & 11 deletions lib/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,20 +170,25 @@ function Schema(obj, options) {
* @api private
*/
function aliasFields(schema, paths) {
paths = paths || Object.keys(schema.paths);
for (const path of paths) {
const options = get(schema.paths[path], 'options');
if (options == null) {
continue;
}
for (const path of Object.keys(paths)) {
let alias = null;
if (typeof paths[path] === 'string') {
alias = paths[path];
} else {
const options = get(schema.paths[path], 'options');
if (options == null) {
continue;
}

const prop = schema.paths[path].path;
const alias = options.alias;
alias = options.alias;
}

if (!alias) {
continue;
}

const prop = schema.paths[path].path;

if (typeof alias !== 'string') {
throw new Error('Invalid value for alias option on ' + prop + ', got ' + alias);
}
Expand Down Expand Up @@ -663,9 +668,50 @@ Schema.prototype.add = function add(obj, prefix) {
}
}

const addedKeys = Object.keys(obj).
map(key => prefix ? prefix + key : key);
aliasFields(this, addedKeys);
const aliasObj = Object.fromEntries(
Object.entries(obj).map(([key]) => ([prefix + key, null]))
);
aliasFields(this, aliasObj);
return this;
};

/**
* Add an alias for `path`. This means getting or setting the `alias`
* is equivalent to getting or setting the `path`.
*
* #### Example:
*
* const toySchema = new Schema({ n: String });
*
* // Make 'name' an alias for 'n'
* toySchema.alias('n', 'name');
*
* const Toy = mongoose.model('Toy', ToySchema);
vkarpov15 marked this conversation as resolved.
Show resolved Hide resolved
* const turboMan = new Toy({ n: 'Turbo Man' });
*
* turboMan.name; // 'Turbo Man'
* turboMan.n; // 'Turbo Man'
*
* turboMan.name = 'Turbo Man Action Figure';
* turboMan.n; // 'Turbo Man Action Figure'
*
* await turboMan.save(); // Saves { _id: ..., n: 'Turbo Man Action Figure' }
*
*
* @param {string} path real path to alias
* @param {string|string[]} alias the path(s) to use as an alias for `path`
vkarpov15 marked this conversation as resolved.
Show resolved Hide resolved
* @return {Schema} the Schema instance
* @api public
*/

Schema.prototype.alias = function alias(path, alias) {
if (Array.isArray(alias)) {
for (const a of alias) {
this.alias(path, a);
}
hasezoey marked this conversation as resolved.
Show resolved Hide resolved
return this;
}
aliasFields(this, { [path]: alias });
return this;
};

Expand Down
14 changes: 14 additions & 0 deletions test/schema.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2867,4 +2867,18 @@ describe('schema', function() {
assert.equal(doc1.domain, mongooseDomain);
assert.equal(doc1.domain, doc2.domain);
});

it('alias (gh-12368)', function() {
const schema = new Schema({ name: String });

schema.alias('name', 'otherName');
assert.equal(schema.aliases['otherName'], 'name');
assert.ok(schema.virtuals['otherName']);

schema.alias('name', ['name1', 'name2']);
assert.equal(schema.aliases['name1'], 'name');
assert.equal(schema.aliases['name2'], 'name');
assert.ok(schema.virtuals['name1']);
assert.ok(schema.virtuals['name2']);
});
});