LINUX.ORG.RU

Как в persistent создать Decimal поле ?

 , decimal, ,


0

1

Хочу хранить числа произвольно точности (финансовые данные, так что Double не канает), во всех база данных есть тип numeric/decimal(x, y) где x и y размер числа и количество знаков после запятой соответственно. В Haskell это либо Fixed либо Data.Decimal из пакета Decimal. А как создать тип и сохранить эти данные ? Вообще, посмотрел по библиотекам, HDBC - топорная библиотека, не имеет возможности добавить свой тип, HSQL - есть тип Decimal, но инстансов дефолтных для преобразования типов нет. Persistence:

data FieldType
    = FTTypeCon (Maybe Text) Text -- ^ optional module, name
    | FTApp FieldType FieldType
    | FTList FieldType
  deriving (Show, Eq, Read, Ord)
Значит можно добавить, видимо надо что-то дописать в TH для биндинга полей типа Fixed/Decimal, или persistent уже умеет ?

derivePersistField «TypeName» кажется. Есть ограничения по классам, но я думаю с этим сам разберёшься.

KblCb ★★★★★
()
Ответ на: комментарий от KblCb

derivePersistField

Не канает, это полная фигня, подохит только для сохранения Enum типов в строку и вытаскивания из строки этих типов обратно в хаскель с помощью show/read соответственно.

Поосиливал немного сноймана, вобщем, есть тайпкласс PersistField, и, похоже, что его и надо инстанцировать для Fixed

Вот что я наваял

instance (HasResolution a) => PersistField (Fixed a) where
  toPersistValue a = PersistText $ T.pack $ show a
  fromPersistValue (PersistDouble d) = Right $ fromRational $ toRational d
  fromPersistValue (PersistText d) = case reads dpt of
    [(a, "")] -> Right a
    _         -> Left $ T.pack $ "Could not read value " ++ dpt ++ " as fixed value"
    where dpt = T.unpack d

  fromPersistValue a = Left $ T.append "Unexpected data value can not be converted to Fixed: " $ T.pack $ show a

  sqlType a = SqlOther $ T.pack $ "NUMERIC(" ++ (show l) ++ "," ++ (show p) ++ ")"
    where
      p = round $ (log $ fromIntegral $ resolution a) / (log 10)
      l = p + 15                --  FIXME: this is maybe not very good
  isNullable _ = False

Теперь поле с типом Fixed должно сохраняться в базе и миграция создает поле NUMERIC(x,y), что меня безмерно радует, но вот тип PersistValue не имеет ни Fixed ни Rational варианта, а ведь именно через этот тип происходит преобразование хаселевого типа данных в нативный тип для базы данных и обратно.

Таким образом, сохранение происходит через преобразование в строку, а чтение через преобразование из Double, который я получаю, когда делаю select ...

Точность, естественно, при этом теряется, можешь убедиться на примерчике.

https://github.com/s9gf4ult/xres

Можно хранить и тупо строкой (как и делает derivePersistField), но тогда нет никакой возможности делать запросы с условиями (>, <, =, >= ...) по этому полю, ведь в базе тип будет varchar, и это меня очень печалит.

Попахивает патчем в persistent, или есть другие варианты ? Можно и без persistent.

s9gf4ult ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.