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

Api restructure #125

Merged
merged 28 commits into from
Apr 1, 2022
Merged

Api restructure #125

merged 28 commits into from
Apr 1, 2022

Conversation

ahmednfwela
Copy link
Collaborator

@ahmednfwela ahmednfwela commented Nov 5, 2021

This PR is to restructure the API under the following targets

  1. a DBContext targets a single database
  2. a MongoContext targets a MongoDB connection which allows accessing multiple DBContexts (multiple databases)
  3. the static api is to be routed through a singleton MongoContext with a singleton DBContext for convenience to use when no DI containers are being used
  4. MongoContexts and DBContexts should be cheap to create, cachable and configurable
  5. MongoContext will store connection-level mappings and convention, while DBContext will store Database-level mappings and conventions

solves #124
solves #123
solves #126

@dj-nitehawk
Copy link
Owner

@ahmednfwela we can drop support for netstandard2.0 and bring it up to 2.1 if it's gonna be of some help.

also pls keep the performance benchmarks in mind as well. we don't wann loose too much when compared against the official driver.

and have you had a chance to see if relationships can be supported with your restructure/multi-tenancy?

also if there's anything i can do to help, pls let me know.

good luck brotha!

@ahmednfwela
Copy link
Collaborator Author

  • I don't think upgrading the TargetFramework will be necessary, I was just testing something with 2.1.
  • As for the performance, it would automatically get better since we are removing the overhead of maintaining a reference to all the databases.

For relationships, here is what we could do:
The current api handles the relationships using Many/One objects, and they need to get a reference to IMongoCollection and this is where the problem happens.
To get a reference to an IMongoCollection you need the DBContext, which means you need to somehow tell the model object about the DBContext, this was easy when the static DB class was used, but not anymore.

To solve this we have 2 ways

  1. Pass the DBContext to the model
  2. Change Many/One so that they don't depend on IMongoCollection

In my opinion the second option is better, since it's less intrusive and more maintainable, but it will break the existing api since it depends strictly on IMongoCollection.

I will push some commits with what I think should be the right pattern to use, and see if it's ok.

@dj-nitehawk
Copy link
Owner

yeah no worries. let's break the many/one api if need be.
if all pans out ok, we can release it as a major version jump with breaking changes. i'm sure ppl would understand.
it would future-proof a lot of things.

@ahmednfwela
Copy link
Collaborator Author

@dj-nitehawk please check the latest commit, I split Find into 2 classes

  1. FindBase<T, TProjection, TSelf> is only responsible for building the query, and doesn't care about what collection it runs on.
  2. Find<T, TProjection> takes query information from FindBase and adds DBContext and IMongoCollection on top of it, which makes the query executable.

if you like this pattern, we can generalize it for the other classes too
and it won't break the public API, since all the constructors are internal

@dj-nitehawk
Copy link
Owner

yeah looks good... go for it 👍

* Major refactoring
* No more repeating code in builders
* Multi-tenancy is per database now instead of per collection, which should be cleaner
@ahmednfwela
Copy link
Collaborator Author

ahmednfwela commented Nov 5, 2021

@dj-nitehawk I refactored the builders now, and they look way cleaner than before

P. S. also enabled nullable in the entire project

@dj-nitehawk
Copy link
Owner

yes i've been following your work. looks awesome!!!
and yeah i was gonna enable nullable myself. you beat me to it ;-)
good job so far man!!!
looking forward to testing this...

@bobbyangers
Copy link

@ahmednfwela I am reviewing your work, it's moving along quite well.

It seems we have many common coding style.

Note1: (Maybe) Instead of MongoContext, consider renaming to ServerContext; it is more general

Note2: I think we don't need to "hardcode" the notion of tenantId into the database naming; and leave that logic to the Dependency injection that way we don't need to "force" anyone to use a specific pattern for naming the DBs.
For example, we might use a pattern similar to Finbuckle.Multinant and store the tenantinfo/db mapping in a tenant database. (i'll write the extension, once you are done with this pass)

@ahmednfwela
Copy link
Collaborator Author

@bobbyangers yes, I think I will remove the tenant id altogether and let the tenancy handling out of the Context
and i renamed MongoContext to MongoServerContext

@bobbyangers
Copy link

@ahmednfwela, it's looking better and better.

if I can do something to help, let me know.

@ahmednfwela
Copy link
Collaborator Author

@bobbyangers maybe you could start on supporting multi-tenancy while I do the remaining refactoring?
if you needed to expose anything from the public api I will help with it

@bobbyangers
Copy link

@bobbyangers maybe you could start on supporting multi-tenancy while I do the remaining refactoring? if you needed to expose anything from the public api I will help with it

Hi @ahmednfwela, yes I will do that, but as an contrib extension, not in the main package.

/// <summary>
/// Access the DataStreamer class for uploading and downloading data
/// </summary>
public DataStreamer Data => streamer ??= new DataStreamer(this);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to break the api here? or will you be adding this back in later?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, since DataStreamer needs to get FileChunk collection, it needs to know about the DBContext, so we would either have to

  1. pass the DBContext to the FileEntity just to be used in new DataStreamer(this, db);
  2. or leave the creation of DataStreamer to the DBContext (better)

@ahmednfwela
Copy link
Collaborator Author

@dj-nitehawk @bobbyangers I made the DBContext api fully customizable, each method can be passed an optional string? collectionName or IMongoCollection<T>? collection
which can override the default behavior of the collection resolution.

this means that we don't even assume collections are in the same database as the context, e.g.

Context.Find<T>(collection: someCollectionInAnotherDataBase)

this is useful for applying OnBeforeSave and OnBeforeUpdate on arbitrary collections, and for multi tenancy

@bobbyangers
Copy link

@ahmednfwela can you reinvite me please ? I seems, that my initial confirmation was incomplete.

Also; I also wanted to check with you; is the project compiling now ?

@ahmednfwela
Copy link
Collaborator Author

@bobbyangers well, not yet, I am a little busy nowadays, so I didn't have time to finish yet.

@bobbyangers
Copy link

bobbyangers commented Nov 19, 2021 via email

@dj-nitehawk
Copy link
Owner

@ahmednfwela you should pull the latest changes from dj-nitehawk:multi-tenancy branch. did a small hotfix for #146

@bobbyangers
Copy link

@ahmednfwela what is the status of the work ? And what is left to do ?

@ahmednfwela
Copy link
Collaborator Author

I am currently researching how to do relationships efficiently.
I am also migrating the static api to use singleton pattern instead, but to be honest I would rather just remove it altogether, since it's not worth the effort

@dj-nitehawk
Copy link
Owner

@ahmednfwela ok let's remove the static stuff if it makes it easier to maintain the project in the long-run. so yeah go ahead, rip that shit out 😜

@ahmednfwela
Copy link
Collaborator Author

well, that took a load off my chest

@dj-nitehawk
Copy link
Owner

@ahmednfwela have you given any thought to how migrations should be done now?
where are we gonna store the migration history when it comes to multi-tenant?
and are we gonna execute each new migration against all tenant databases, etc. etc.

@ahmednfwela
Copy link
Collaborator Author

well, I am going to move migration to be per DBContext as well, this way we don't care how many databases the user has

@dj-nitehawk
Copy link
Owner

@ahmednfwela i added you as a collaborator to this repo. here's what i'm thinking about how to proceed with this refactor.

  1. let's bring in your current code to a new branch on this repo called "vNext"
  2. work/commit directly on that branch.
  3. once we have tests passing, let's release an alpha version so we can test it in the wild.
  4. then create a new "vNext-Docs" branch and get the docs ready for the v22
  5. once the new codebase is stable enough (after a couple of betas), we'll move the current master branch to a "v21-Legacy" branch and make vNext the master.

what do you think?

@ahmednfwela
Copy link
Collaborator Author

sure, that sounds like a good plan!

@ahmednfwela
Copy link
Collaborator Author

vNext should be branched off from multi-tenancy though

@dj-nitehawk
Copy link
Owner

dj-nitehawk commented Dec 28, 2021

vNext should be branched off from multi-tenancy though

yeah go ahead and create it however you like. or just rename "multi-tenancy" to "vNext" and pull in your changes.

@ahmednfwela
Copy link
Collaborator Author

done

@dj-nitehawk
Copy link
Owner

@ahmednfwela will you merge and close this PR into vnext? or you wanna keep working on your fork and merge later?

@ahmednfwela
Copy link
Collaborator Author

I will merge it to vNext once it can actually compile, then we can do multiple PRs onto vNext later

@ahmednfwela
Copy link
Collaborator Author

ahmednfwela commented Dec 28, 2021

I also removed all dependency on IEntity/IEntity<T> and move their functionality to extensions
this means that queries can run on ANY type, instead of only types implementing IEntity

@ahmednfwela
Copy link
Collaborator Author

@dj-nitehawk i will merge this for now (even tho project isn't building)

@ahmednfwela ahmednfwela marked this pull request as ready for review April 1, 2022 04:28
@ahmednfwela ahmednfwela merged commit c4eed0b into dj-nitehawk:vnext Apr 1, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants