yesodweb / persistent

Persistence interface for Haskell allowing multiple storage methods.
MIT License
465 stars 294 forks source link

Could we add search indexes? #919

Open jappeace opened 5 years ago

jappeace commented 5 years ago

A client of mine has a bunch of constraints on the table that are simply 'key' (mysql). I wouldn't know how to model that in a migration, I believe they're just search indexes: https://stackoverflow.com/questions/924265/what-does-the-key-keyword-mean

I think postgress supports this too, by manually creating an index: https://devcenter.heroku.com/articles/postgresql-indexes And I know mongo does: https://docs.mongodb.com/manual/indexes/

So I'm not asking for a unique constraint, just a way to express an index in the migrations to make queries go faster.

parsonsmatt commented 5 years ago

This would be great to have! A rough implementation plan would look like:

jappeace commented 5 years ago

Seems pretty do-able, I may look into that once I'm ready to adopt the table in question fully.

parsonsmatt commented 5 years ago

You can do this manually with raw SQL and making your own migrations -

keyMigrations :: Migration
keyMigrations = do
  addMigration True "CREATE INDEX IF NOT EXISTS ON user (name)"
  -- etc

See the functions here for more info

You can probably even write mkSearchIndex :: PersistEntity entity => EntityField entity field -> Migration to make the transition easier, though I'd have to study the docs a bit to see how to get there.

jappeace commented 5 years ago

Hey that's a good idea! Especially since I don't expect my Haskell code to do anything with the fact there is an index or not, so we shouldn't need to model that in the QQ.

You can probably even write mkSearchIndex :: PersistEntity entity => EntityField entity field -> Migration

Do migrations 'know' about back ends? I could at least pull out the name from the fieldDef, but the rest of the query would be mysql only.

parsonsmatt commented 5 years ago

SqlBackend's migration is only based on an EntityDef at the moment, so it's not really sufficient for this right now.

TomMD commented 4 years ago

Related to this issue, the Haskell mongoDB index creation is broken so any attempt at building and testing this feature will be blocked at least on that backend.

parsonsmatt commented 4 years ago

FWIW: I am opposed to putting this in the QQ DSL. I'd much rather write some documentation and show how the Migration type is actually a monad and can be composed nicely.

share [mkMigrate "migrateAll", ...] [persistLowerCase| ... |]

runMigrations :: SqlPersistM ()
runMigrations = runMigration $ do
  migrateAll
  createSearchIndex UserName

Adding createSearchIndex :: (PersistEntity rec) => EntityField rec typ -> Migration should not be terribly difficult.

Vlix commented 3 years ago

This sounds like it'd be pretty nice to have. I might want to pick this up sometime soon...

joeyh commented 1 year ago

There may be something that prevents using the addMigration technique with persistent-sqlite. I'm getting:

Database migration: manual intervention required. The unsafe actions are prefixed by '***' below:

*** CREATE INDEX IF NOT EXISTS idx_cid ON content_identifiers (cid);

I used addMigration True so it's not marked unsafe and it seems it must be failing to parse it. Pasting the same statement into sqlite3 successfully creates the index.

parsonsmatt commented 1 year ago

Ah, the Boolean blindness bites again - True means unsafe.

sorki commented 10 months ago

Ah, the Boolean blindness bites again - True means unsafe.

Just got bitten by that as well and the docs state

Bool: Is the migration safe to run? (eg a non-destructive and idempotent update on the schema)

(EDIT: only the old version of docs, it is actually fixed in most recent one)

~So it seems that True should mean safe,~ anyway an enum like Safe | Unsafe would be easier to reason about I think.