-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
fix: multiple instances of the same repository class #1302
Conversation
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.
👏
const model1 = new DefaultCrudRepository(Note, ds).modelClass; | ||
const model2 = new DefaultCrudRepository(Note, ds).modelClass; | ||
|
||
expect(model1 === model2).to.be.true(); |
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.
Does deep assertion not work with shouldjs
?
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.
We can use expect(model1).to.be.exactly(model2);
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.
We can. My experience is that equality assertion produces an error message that's rather unhelpful, because it it lists all model properties and properties of these properties. Because a model is attached to a datasource that has a reference to a model builder, eventually all models registered with the data source are printed in the diff. That's why I decided to use this form, because really all we want to see is whether the two models are the same V8 entity or not.
docs/site/Repositories.md
Outdated
@@ -9,7 +9,8 @@ summary: | |||
--- | |||
|
|||
A Repository is a type of _Service_ that represents a collection of data within | |||
a DataSource. | |||
a DataSource. A repository class is a lightweight object that's cheap to create, |
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.
cheap
tends to have a negative connotation (at least in my head). Can we use lightweight
or easy
?
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.
How about something along the following lines?
A repository class is a lightweight object, its instances can be created with low runtime overhead, (etc.)
// The backing persisted model has been already defined. | ||
this.modelClass = model as typeof juggler.PersistedModel; | ||
return; | ||
} |
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.
There is a flaw in this PR:
- A 3.x model classes can only be attached to one data source.
- We introduce
Repository
so that it can representmodelClass + dataSource
- Each instance of
Repository
should have its own 3.x model class - We should use
bindModel
instead ofmodel.attachTo()
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.
A 3.x model classes can only be attached to one data source.
We introduce Repository so that it can represent modelClass + dataSource
Agreed.
Each instance of Repository should have its own 3.x model class
I disagree for two reasons:
- A datasource maintains a model builder with a registry of all models. When I attach the same LB4 model to the same LB3 datasource, and the repository creates a new PersistedModel each time, then each call of the repository constructor will override the modelBuilder entry.
- Creating a new Model class is expensive performance wise.
In my proposal, we will have a single LB3 PersistedModel for each pair of LB4 Model + LB3 dataSource. If you attach the same LB4 Model to multiple dataSources, then we will have multiple LB3 PersistedModels, one for each dataSource.
Is there any specific problem you are concerned about?
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.
Each instance of Repository should have its own 3.x model class
I would like to know why we can't re-use the model class if it's already defined as proposed in this PR?
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.
The 3.x model classes maintain two states:
- The model definition
- The attached data source
For example, a Customer
model can only be attached to mongodb
or mysql
but we cannot have the same model definition to be used with mongodb
or mysql
unless we subclass it.
In LB4, we subclass Customer
for each repository instance to delegate to juggler model methods without interfering with other instances. For example:
export class MyController {
@repository(Customer, 'mongodb')
private mongoRepo;
@repository(Customer, 'mysql')
private mysqlRepo;
}
@bajtos Please note in LB 3.x, all data source instances share the same modelBuilder
if it's from loopback
module. See https://github.com/strongloop/loopback/blob/master/lib/registry.js#L362.
If in LB4, we always create DataSource instances with its own modelBuilder, your PR should be fine.
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.
If in LB4, we always create DataSource instances with its own modelBuilder, your PR should be fine.
Yes, that's the case so far - in LB4, each DataSource has its own model builder.
d40b900
to
ea3370e
Compare
@raymondfeng As I commented above, each LB4 DataSource has its own model builder. Given that, are you ok with landing this pull request? @virkt25 I removed the word "cheap" from the docs, per our discussion above. Does the patch LGTY now? |
The build failure on Node.js 10.x is unrelated to my changes. Looks like one of our dependencies and/or Node.js core is using experimental
|
How to troubleshoot the problem: run the tests with
The problem is caused by fs-extra - see jprichardson/node-fs-extra#577 |
ea3370e
to
e18ecf3
Compare
Rebased on top of the latest master, all CI checks are green again 💚 |
Fix DefaultCrudRepository to re-use legacy juggler Models across all instances of the same Repository class. Before this change, each call of DefaultCrudRepository constructor was redefining the backing persisted model. This commit adds a caching mechanism to DefaultCrudRepository: when setting up a backing model, we check datasource's modelBuilder registry to find if the backing model was not already created by an older instance of the repository.
e18ecf3
to
0a1f960
Compare
@bajtos I have rebased the PR against the latest master. |
@bajtos I merged the PR for you. |
Fix DefaultCrudRepository to re-use legacy juggler Models across all instances of the same Repository class.
Before this change, each call of DefaultCrudRepository constructor was redefining the backing persisted model.
This commit adds a caching mechanism to DefaultCrudRepository: when setting up a backing model, we check datasource's modelBuilder registry to find if the backing model was not already created by an older instance of the repository.
See #1032 and #995.
Checklist
npm test
passes on your machinepackages/cli
were updatedexamples/*
were updated