-
Notifications
You must be signed in to change notification settings - Fork 169
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
Add indices support (WIP) #335
base: travis/beam-0.8.0.0
Are you sure you want to change the base?
Add indices support (WIP) #335
Conversation
3e9e642
to
287341f
Compare
Hello! Wow.. Thanks! This is a lot to digest, but right off the bat, I'll ask you to rebase on top of the beam-0.8.0.0 branch, since that represents the next release. There'll be a few changes you'll have to make to get it compiling. The upside is that it should trigger a gitlab CI build, which will have to pass before I merge. Additions to the manual would be nice. I'm still getting through the code. Travis |
|
||
import Database.Beam.Schema.Tables | ||
|
||
-- Some day it should have more options and allow to modify them depending on the backend. |
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.
When merged, add a ticket for this to the issue reporting system
-- instances for all of them. | ||
-- | Traverses the given table and for every field which is some 'PrimaryKey' | ||
-- makes corresponding SQL index, this allows "JOIN"s on this table perform nicely. | ||
instance {-# OVERLAPPABLE #-} |
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.
Why are these instances overlappable?
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.
Well, I'm not sure whether is it a good choice, but I saw that there are plans to support many different entities type, while we want to have indices only for TableEntities
. It looked like the one who will enable support for those other entities should not bother about indices at all, thus a default overlappable instance.
Should I define instances for each entity type explicitly instead?
-- | Provide options for an automatically created index, which is caused by a primary key | ||
-- of one table being embedded into another. | ||
-- This typeclass is only needed to be defined for inter-table references (see ':->'). | ||
class IndexFromReference reference where |
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 issue I see right now is that tables should be able to have two foreign keys that refer to the same table type at the haskell level, but really refer to two different tables at the database level.
For example
data TwoKeyT f =
TwoKey {
_key1 :: PrimaryKey RefT f
_key2 :: PrimaryKey RefT f
}
data RefT f = Ref { _field1 :: C f Text, _field2 :: C f Int }
data Database entity = Database { _ref1 :: entity (TableEntity RefT), _ref2 :: entity (TableEntity RefT), _twoKey :: entity (TableEntity TwoKeyT) }
How would I make it so that it knows that _key1 refers to _ref2 and _key2 to _ref1 (or vice versa). I believe the way it is now, each type is uniquely linked to one database table, which is a large constraint.
One way to get around this that would also (I think) have the benefit of removing the instance overlap is to not use the type class mechanism and require the user to construct an appropriate value.
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 agree this is a major problem. In case of this implementation via type class mechanism a workaround is to parametrize table type with a phantom type parameter, thus making different tables of the same type distinguishable in a Haskell code.
However, making user explicitly make a construct which describes options for the generated indices seems to be virtually better in several ways. Doing so may be tricky if we still want the type system to enforce the user to specify indices for all embedded PrimaryKey
s present; I described my raw suggestion right below this code, we could discuss it :)
Oh, having CI checking my work would be really nice! |
Just regular beam-0.8.0.0. I'll get rid of the other ones. They're all merged. |
That's weird, I see no plain |
Ah, thanks. I wasn't sure it was that branch you were talking about because |
The latest commit there should be 377596e |
d4a3c4d
to
0bb3279
Compare
Oh right, I searched in my forked repository. Thanks for helping with figuring this out, I'm rebasing. |
You'll need to resolve conflicts too to get CI working. |
Yeah, it's gonna take a while :) |
This includes: * Manual indices definition; * Automatic detection of indices required for performant JOINs; * Manual and automatic index creation/deletion via `ADD/DROP INDEX` (without SQLite support)
0bb3279
to
f861d40
Compare
fe622cd
to
f861d40
Compare
d0f96d1
to
6798056
Compare
Finally, I rebased upon beam-0.8.0.0 branch. Now there are a couple of small issues:
|
Oh, wow, this looks really cool. Any chance of this getting resurrected and merged? |
@tp-woven You're welcome to take it over! I'm happy to review but unfortunately don't have the time for major feature development on Beam these days. |
Yeah, @tp-woven I would be glad if you manage to take this work or pick it as inspiration for your own implementation, especially since @kmicklas approved this. Now I cannot allocate time to this. If I remember correctly, this PR mostly handles the core part (not tested at all) but may need a decent update of the migration package. |
Thanks, I'll try to take over. Fair warning: I'm a Haskell noob, so it may take a while... 😅 |
Motivation
Currently, there is no way to deal with the database schema purely via Haskell code, which is not good at least because when we define our schema in raw SQL, we get table and fields names defined in several places.
I'm planning to make SQL engine know about foreign key constraints in the next PR, and these two seem to provide a basis for moving away from manual schemas definition completely.
PR Details
The following features are implemented:
Manual indices definition.
Here a user can provide a list of indices on the per-table basis, each index is defined by a sequence of its fields and its settings (only most basic settings are supported for now). With syntax as the following.
Automatic indices detection.
A user can make a
DatabaseIndices
(which is similar toDatabaseSettings
but contains information about indices correspondingly) viadefaultDbIndices
, which gathers indices on those columns which are assumed to participate inJOIN
s.Later the user can add these indices to the custom ones via dedicated function
mergeDbIndices
, or immediately useaddDefaultDbIndices
.Manual/automatic migrations support.
Previously gathered indices are converted to
TableChecks
and added toCheckedDatabaseSettings
.Two action providers are supplied:
ADD INDEX
andDROP INDEX
.Herewith, unfortunately, there is no SQLite support, since there is no way to modify indices of the existing table there. A common workaround is to rename the table, create a new one with the desired indices and copy all the data, but I'm not yet ready to write copying action providers, although generally, that scheme seems to be perfectly discoverable with existing automatic migration means.
Testing.
Haddock: builds.
Extend the manual.
Notes
I have a set of
TODO
s remained where I'm not sure about proper design choice, would appreciate hearing your point of view on this.Also, I added
.stylish-Haskell.yaml
which corresponds to the style of this project, otherwise I get pretty mad diffs each time I save a file.