Sometimes you need to use hardcoded string literals in your program. There is just not enough benefit of introducing dynamic configuration (config files, CLI options, etc), because values almost never change. And if they would change, it is easy to modify values in the source code.
I came up with the following pattern or keeping related configuration values close to each other.
data ClientImport a = (AsRelation a) => ClientImport
{ forecast :: a
, inventory :: a
, products :: a
, reports :: a
}
clientImport :: ClientImport TableRelation
clientImport =
ClientImport
{ forecast = define "forecast"
, inventory = define "inventory"
, products = define "products"
, reports = define "reports_legacy"
}
where
define nm = TableRelation $ "client_imports" <> nmThe reason of introducing a data structure would be obvious after looking at usage site.
{-# LANGUAGE OverloadedRecordDot #-}
import Project.Legacy qualified as Legacy
available = do
source <- from Legacy.clientImport.inventory
where_ $ source ^^. "status" !=. lit SoldOverloadedRecordDot extensions allows to have two dots in Legacy.clientImport.inventory, where
Legacyis a qualified alias of theProject.LegacyimportclientImportis a function name imported fromProject.Legacy, has typeClientImport TableRelationinventoryis a field name accessor of theClientImportdata structure