-
Notifications
You must be signed in to change notification settings - Fork 362
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: add unique index support on create for in-memory connector #1672
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -255,6 +255,21 @@ Memory.prototype._createSync = function(model, data, fn) { | |
this.collection(model, {}); | ||
} | ||
|
||
var indexes = this._models[model].model.definition.indexes(); | ||
for (var idx in indexes) { | ||
var idxPropName = idx.substring(0, idx.indexOf('_index')); | ||
if (indexes[idx].unique === true) { | ||
for (var instId in this.cache[model]) { | ||
var inst = JSON.parse(this.cache[model][instId]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This implementation will scale poorly. When there are 1000 records, you have to JSON parse 1000 records to check for uniqueness. That's a lot of CPU work! IMO, UNIQUE INDEX should be implemented using a Set:
Whenever adding a new property value, report an error if the property value already exists in the Set. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The reason I have to use JSON parse is because we stringify the model instances to store in the cache :(. However, I like that approach and I'm trying it out. I think it will work well with multiple-key unique indexes too. |
||
if (inst[idxPropName] === data[idxPropName]) { | ||
var duplicateIndexError = new Error(g.f('Duplicate entry for %s.%s', model, idxPropName)); | ||
duplicateIndexError.statusCode = duplicateIndexError.status = 409; | ||
return fn(duplicateIndexError); | ||
} | ||
} | ||
} | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch! |
||
if (this.collection(model)[id]) { | ||
var error = new Error(g.f('Duplicate entry for %s.%s', model, idName)); | ||
error.statusCode = error.status = 409; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -677,6 +677,24 @@ describe('Memory connector', function() { | |
}); | ||
}); | ||
|
||
it('should refuse to create object with duplicate unique index', function(done) { | ||
var ds = new DataSource({connector: 'memory'}); | ||
var Product = ds.define('ProductTest', {name: {type: String, index: {unique: true}}}, {forceId: false}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I see this is an existing & already documented syntax 👍 https://loopback.io/doc/en/lb3/Model-definition-JSON-file.html#indexes I find this statement as too long & difficult to read when on a single line, could you please split it into multiple lines (e.g. using "one arg per line" rule). |
||
ds.automigrate('ProductTest', function(err) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. juggler v4 requires Node.js 8+. In new code, we should stop using callbacks and use async/await instead. In #1671, I am fixing eslint config to allow async functions. |
||
if (err) return done(err); | ||
|
||
Product.create({name: 'a-name'}, function(err, p) { | ||
if (err) return done(err); | ||
Product.create({name: 'a-name'}, function(err) { | ||
should.exist(err); | ||
err.message.should.match(/Duplicate/i); | ||
err.statusCode.should.equal(409); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('automigrate', function() { | ||
var ds; | ||
beforeEach(function() { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this string manipulation hacky and fragile. Let's fix
definition.indexes()
to copy the property name into index definition.