haskell - How to let default values come from the database? -


why user object still have nothing createdat , updatedat? why fields not getting assigned database?

share [mkpersist sqlsettings, mkmigrate "migrateall"] [persistlowercase| user   email string   createdat utctime maybe default=current_time   updatedat utctime maybe default=current_time   deriving show |]  main = runsqlite ":memory:" $   runmigration migrateall   userid <- insert $ user "saurabhnanda@gmail.com" nothing nothing   liftio $ print userid   user <- userid   case user of     nothing -> liftio $ putstrln ("coulnt find userid=" ++ (show userid))     u -> liftio $ putstrln ("user=" ++ (show user)) 

output:

userkey {unuserkey = sqlbackendkey {unsqlbackendkey = 1}} user=just (user {useremail = "saurabhnanda@gmail.com", usercreatedat = nothing, userupdatedat = nothing}) 

(edit: see solution below using triggers)

the problem: default values don't override explicitly setting column null

per sqlite docs:

the default clause specifies default value use column if no value explicitly provided user when doing insert.

the issue when persistent doing insert, it's specifying createdat , updatedat columns null:

[debug#sql] insert "user"("email","created_at","updated_at") values(?,?,?); [persisttext "saurabhnanda@gmail.com",persistnull,persistnull] 

to reach conclusion, modified snippet add sql logging (i copied source of runsqlite , changed log stdout). used file instead of in-memory database open database in sqlite editor , verify default values being set.

-- pragmas , imports taken snippet in yesod book. of them may superfluous. {-# language emptydatadecls             #-} {-# language flexiblecontexts           #-} {-# language gadts                      #-} {-# language generalizednewtypederiving #-} {-# language multiparamtypeclasses      #-} {-# language overloadedstrings          #-} {-# language quasiquotes                #-} {-# language templatehaskell            #-} {-# language typefamilies               #-} import database.persist import database.persist.sqlite import database.persist.th import control.monad.io.class (liftio) import data.time import control.monad.trans.resource import control.monad.logger import control.monad.io.class import data.text  share [mkpersist sqlsettings, mkmigrate "migrateall"] [persistlowercase| user   email string   createdat utctime maybe default=current_time   updatedat utctime maybe default=current_time   deriving show |]  runsqlite2 :: (monadbasecontrol io m, monadio m)           => text -- ^ connection string           -> sqlpersistt (loggingt (resourcet m)) -- ^ database action           -> m runsqlite2 connstr = runresourcet                   . runstdoutloggingt                   . withsqliteconn connstr                   . runsqlconn  main = runsqlite2 "bar.db" $   runmigration migrateall   userid <- insert $ user "saurabhnanda@gmail.com" nothing nothing   liftio $ print userid   user <- userid   case user of     nothing -> liftio $ putstrln ("coulnt find userid=" ++ (show userid))     u -> liftio $ putstrln ("user=" ++ (show user)) 

here's output get:

max@maximilians-mbp /tmp> stack runghc sqlite.hs run outside project, using implicit global project config using resolver: lts-3.10 implicit global project's config file: /users/max/.stack/global/stack.yaml migrating: create table "user"("id" integer primary key,"email" varchar not null,"created_at" timestamp null default current_time,"updated_at" timestamp null default current_time) [debug#sql] create table "user"("id" integer primary key,"email" varchar not null,"created_at" timestamp null default current_time,"updated_at" timestamp null default current_time); [] [debug#sql] insert "user"("email","created_at","updated_at") values(?,?,?); [persisttext "saurabhnanda@gmail.com",persistnull,persistnull] [debug#sql] select "id" "user" _rowid_=last_insert_rowid(); [] userkey {unuserkey = sqlbackendkey {unsqlbackendkey = 1}} [debug#sql] select "email","created_at","updated_at" "user" "id"=? ; [persistint64 1] user=just (user {useremail = "saurabhnanda@gmail.com", usercreatedat = nothing, userupdatedat = nothing}) 

edit: solution using triggers:

you can implement created_at , updated_at columns triggers. approach has nice advantages. there's no way updated_at enforced default value anyway, need trigger if want database (and not application) manage it. triggers solve updated_at being set when executing raw sql queries or batch updates. here's solution looks like:

create trigger set_created_and_updated_at after insert on user begin update user set created_at=current_timestamp, updated_at=current_timestamp user.id = new.id; end  create trigger set_updated_at after update on user begin update user set updated_at=current_timestamp user.id = new.id; end 

now output expected:

[debug#sql] insert "user"("email","created_at","updated_at") values(?,?,?); [persisttext "saurabhnanda@gmail.com",persistnull,persistnull] [debug#sql] select "id" "user" _rowid_=last_insert_rowid(); [] userkey {unuserkey = sqlbackendkey {unsqlbackendkey = 1}} [debug#sql] select "email","created_at","updated_at" "user" "id"=? ; [persistint64 1] user=just (user {useremail = "saurabhnanda@gmail.com", usercreatedat = 2016-02-12 16:41:43 utc, userupdatedat = 2016-02-12 16:41:43 utc}) 

the main downside trigger solution it's slight hassle set triggers.


Comments

Popular posts from this blog

sublimetext3 - what keyboard shortcut is to comment/uncomment for this script tag in sublime -

java - No use of nillable="0" in SOAP Webservice -

ubuntu - Laravel 5.2 quickstart guide gives Not Found Error -