2014-07-01 20 views
7

Ho una chiamata ajax che invia json a un instradamento in Yesod e voglio che il percorso analizzi il jSON e lo inserisca direttamente nel database. Nel mio file di modello hoInserisci timestamp di default in fromJson

createtime UTCTime default=now() 

che impedisce l'analisi del json poiché il client non invia il tempo di creazione. Ho provato a scrivere il mio parseJson per le voci di registro, ma non sono riuscito a inserire un valore predefinito in UTCTime poiché getCurrentTime restituisce un valore nella monade IO. Mi piacerebbe che il database impostasse il valore, se possibile.

L'unica cosa che posso pensare a questo punto è di creare un tipo come LogEntryWithoutTime, analizzare il JSON in quello e convertirlo in un LogEntry. C'è un modo più semplice?

Modifica: Mostriamo tre diversi errori per aggiungere getCurrentTime all'analisi JSON. In primo luogo, l'intento è quello di analizzare la creatività se disponibile e l'impostazione predefinita su getCurrentTime sul server. Questo non è giusto comunque, dal momento che non dovremmo fare affidamento sul tempo del cliente.

instance FromJSON Log where 
    parseJSON (Object o) = Log 
     <$> o .: "userid" 
     ... 
     <*> o .:? "createtime" .!= liftIO getCurrentTime 

L'errore è

Model.hs:58:32: 
Couldn't match expected type ‘UTCTime’ 
      with actual type ‘m0 UTCTime’ 
In the second argument of ‘(.!=)’, namely ‘liftIO getCurrentTime’ 
In the second argument of ‘(<*>)’, namely 
    ‘o .:? "createtime" .!= liftIO getCurrentTime’ 

In secondo luogo, cerco di ottenere solo l'ora corrente.

<*> liftIO getCurrentTime 

e ottengo l'errore

Model.hs:58:9: 
No instance for (MonadIO 
        aeson-0.7.0.6:Data.Aeson.Types.Internal.Parser) 
    arising from a use of ‘liftIO’ 
In the second argument of ‘(<*>)’, namely ‘liftIO getCurrentTime’ 

Se cambio la linea di

<*> getCurrentTime 

allora ottengo

Model.hs:58:9: 
Couldn't match type ‘IO’ 
       with ‘aeson-0.7.0.6:Data.Aeson.Types.Internal.Parser’ 
Expected type: aeson-0.7.0.6:Data.Aeson.Types.Internal.Parser 
       UTCTime 
    Actual type: IO UTCTime 
+0

Hai scoperto questo problema? Sto lottando con esso ora. –

+0

Siamo spiacenti, non sono stato in grado di trovare una buona soluzione. – user3776949

risposta

1

La cosa con l'attributo default definito un modello è t ha ancora bisogno di definire tutti i valori quando le entità persistenti. I valori predefiniti sono solo per le migrazioni automatiche e le definizioni dello schema, per quanto ne so.

Provare a sollevare lo getCurrentTime dall'IO monade (con liftIO).

+0

Vedo che il file del modello non ha alcun effetto sul codice Haskell, quindi ho finito per scrivere SQL raw per inserire la riga. Ho provato a usare liftIO quando ho postato questa domanda e non ha funzionato, ma non ricordo l'errore esatto. Penso che stia cercando di metterlo in un'altra monade, ma non c'era altra monade. – user3776949

+0

Nessuna istanza per (MonadIO aeson-0.8.0.2: Data.Aeson.Types.Internal.Parser) –

0

Sto affrontando essenzialmente lo stesso problema ora. Il mio pensiero attuale è che, dal momento che non mi aspetto che l'utente mi fornisca un record completo, non dovrei modellarlo in questo modo. Invece, dovrei modellare il corpo della richiesta che mi aspetto dall'utente e trasformarlo da solo per l'archiviazione.

Quindi, si può avere il concetto di un PartialLog, che ha solo i campi che ci si aspetta che l'utente da inviare:

data PartialLog = PartialLog { partialLogMessage :: Text } 

allora si potrebbe avere una funzione che colma le lacune e vi fornisce un record completo:

{-# LANGUAGE RecordWildCards #-} 

logFromPartial :: PartialLog -> UserId -> IO Log 
logFromPartial p u = do 
    let logUserId = u 
     logMessage = partialLogMessage p 
    logCreatetime <- liftIO getCurrentTime 
    return Log{..} 

nb Sto passando il UserId perché potremmo volere che quel valore provenga dalla sessione autenticata; non c'è bisogno che l'utente ci dica quale sia il loro ID.