Skip to content

Commit fd2cffc

Browse files
authored
fix: 🐛 allow to create documents with non-generated ids (#407)
1 parent a2040e8 commit fd2cffc

File tree

4 files changed

+94
-24
lines changed

4 files changed

+94
-24
lines changed

src/adapters/mongoose.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,12 @@ module.exports = (model, opts) => {
200200
});
201201

202202
function getRequired(fieldInfo) {
203-
return fieldInfo.isRequired === true;
203+
return fieldInfo.isRequired === true
204+
|| (
205+
fieldInfo.path === '_id'
206+
&& !fieldInfo.options.auto
207+
&& fieldInfo.options.type !== mongoose.Schema.ObjectId
208+
);
204209
}
205210

206211
function getValidations(fieldInfo) {

src/services/resource-creator.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ function ResourceCreator(Model, params) {
88

99
function create() {
1010
return new P((resolve, reject) => {
11-
if ('_id' in params) { delete params._id; }
11+
const idField = schema.fields.find((field) => field.field === '_id');
12+
const isAutomaticId = !idField || !idField.isRequired;
13+
14+
if ('_id' in params && isAutomaticId) {
15+
delete params._id;
16+
}
1217

1318
new Model(params)
1419
.save((err, record) => {

test/tests/adapters/mongoose.test.js

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@ describe('adapters > schema-adapter', () => {
677677
});
678678
});
679679

680-
describe('isRequired flag', () => {
680+
describe('"isRequired" flag', () => {
681681
it('should be set to true', async () => {
682682
expect.assertions(2);
683683
const schema = new mongoose.Schema({
@@ -693,9 +693,37 @@ describe('adapters > schema-adapter', () => {
693693
expect(result).toHaveProperty('fields');
694694
expect(result.fields[0].isRequired).toStrictEqual(true);
695695
});
696-
});
697696

698-
describe('"isRequired" flag', () => {
697+
it('should be set to true for non-generated ids', async () => {
698+
expect.assertions(2);
699+
const schema = new mongoose.Schema({
700+
_id: String,
701+
});
702+
const model = mongoose.model('WithNonGeneratedId', schema);
703+
704+
const result = await createSchemaAdapter(model, {
705+
mongoose,
706+
connections: [mongoose],
707+
});
708+
expect(result).toHaveProperty('fields');
709+
expect(result.fields[0].isRequired).toStrictEqual(true);
710+
});
711+
712+
it('should be set to false for generated ids', async () => {
713+
expect.assertions(2);
714+
const schema = new mongoose.Schema({
715+
_id: mongoose.Schema.ObjectId,
716+
});
717+
const model = mongoose.model('WithGeneratedId', schema);
718+
719+
const result = await createSchemaAdapter(model, {
720+
mongoose,
721+
connections: [mongoose],
722+
});
723+
expect(result).toHaveProperty('fields');
724+
expect(result.fields[0].isRequired).toBeUndefined();
725+
});
726+
699727
it('should not appear', async () => {
700728
expect.assertions(2);
701729
const schema = new mongoose.Schema({

test/tests/services/resources-creator.test.js

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import mongooseConnect from '../../utils/mongoose-connect';
66

77
describe('service > resources-creator', () => {
88
let IslandModel;
9+
let CityModel;
910

10-
beforeAll(() => {
11+
beforeAll(async () => {
1112
Interface.Schemas = {
1213
schemas: {
1314
Island: {
@@ -20,27 +21,50 @@ describe('service > resources-creator', () => {
2021
{ field: 'population', type: 'Number' },
2122
],
2223
},
24+
City: {
25+
name: 'City',
26+
idField: '_id',
27+
searchFields: ['name'],
28+
fields: [
29+
{ field: '_id', type: 'String', isRequired: true },
30+
{ field: 'name', type: 'String' },
31+
{ field: 'population', type: 'Number' },
32+
],
33+
},
2334
},
2435
};
2536

26-
return mongooseConnect()
27-
.then(() => {
28-
const IslandSchema = new mongoose.Schema({
29-
name: {
30-
type: String,
31-
validate: {
32-
validator: (v) => ['Kauai', 'Oahu', 'Haiti'].includes(v),
33-
message: (props) => `${props.value} is not valid`,
34-
},
35-
},
36-
population: {
37-
type: Number,
38-
},
39-
});
37+
await mongooseConnect();
38+
const IslandSchema = new mongoose.Schema({
39+
name: {
40+
type: String,
41+
validate: {
42+
validator: (v) => ['Kauai', 'Oahu', 'Haiti'].includes(v),
43+
message: (props) => `${props.value} is not valid`,
44+
},
45+
},
46+
population: {
47+
type: Number,
48+
},
49+
});
50+
51+
IslandModel = mongoose.model('Island', IslandSchema);
52+
await IslandModel.deleteMany({});
53+
54+
const CitySchema = new mongoose.Schema({
55+
_id: {
56+
type: String,
57+
},
58+
name: {
59+
type: String,
60+
},
61+
population: {
62+
type: Number,
63+
},
64+
});
4065

41-
IslandModel = mongoose.model('Island', IslandSchema);
42-
return IslandModel.deleteMany({});
43-
});
66+
CityModel = mongoose.model('City', CitySchema);
67+
await CityModel.deleteMany({});
4468
});
4569

4670
afterAll(() => mongoose.connection.close());
@@ -70,6 +94,14 @@ describe('service > resources-creator', () => {
7094
const result = await new ResourcesCreator(IslandModel, { _id: '56cb91bdc3464f14678934ca', name: 'Haiti' })
7195
.perform();
7296
expect(result).toHaveProperty('name', 'Haiti');
73-
expect(result.id).not.toBe('56cb91bdc3464f14678934ca');
97+
expect(result._id).not.toBe('56cb91bdc3464f14678934ca');
98+
});
99+
100+
it('should not ignore _id for non-generated ids', async () => {
101+
expect.assertions(2);
102+
const result = await new ResourcesCreator(CityModel, { _id: '56cb91bdc3464f14678934ca', name: 'Lyon' })
103+
.perform();
104+
expect(result).toHaveProperty('name', 'Lyon');
105+
expect(result._id).toBe('56cb91bdc3464f14678934ca');
74106
});
75107
});

0 commit comments

Comments
 (0)