{"id":19573934,"url":"https://github.com/hexresearch/micro-dal","last_synced_at":"2025-07-29T01:06:26.295Z","repository":{"id":99626808,"uuid":"258785842","full_name":"hexresearch/micro-dal","owner":"hexresearch","description":null,"archived":false,"fork":false,"pushed_at":"2020-05-19T10:30:03.000Z","size":55,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-26T11:17:16.681Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hexresearch.png","metadata":{"files":{"readme":"readme.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-25T13:44:23.000Z","updated_at":"2020-05-19T10:30:07.000Z","dependencies_parsed_at":"2023-04-10T04:49:16.715Z","dependency_job_id":null,"html_url":"https://github.com/hexresearch/micro-dal","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/hexresearch/micro-dal","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hexresearch%2Fmicro-dal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hexresearch%2Fmicro-dal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hexresearch%2Fmicro-dal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hexresearch%2Fmicro-dal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hexresearch","download_url":"https://codeload.github.com/hexresearch/micro-dal/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hexresearch%2Fmicro-dal/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267613067,"owners_count":24115577,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-28T02:00:09.689Z","response_time":68,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-11T06:37:04.600Z","updated_at":"2025-07-29T01:06:26.266Z","avatar_url":"https://github.com/hexresearch.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# micro-dal\n\nThe lightweight Data Access Layer\n\n```haskell\n      withEngine \"mydatabase.sqlite\" $ \\eng -\u003e do\n        withTransaction eng $ do\n          mapM_ (store @MyDataType eng) values\n\n        values \u003c- listAll @MyDataType eng\n```\n\n## Why\n\nTo decouple the programs from the specific of the data storage.\n\nTo make the work with persistent data simple and provide a possibility to evolve from a naive\napproach during the prototyping to enterprise level gradually, without changing the client's code.\n\nSome ideas behind this library are taken from Martin Fowler's books, Craig Larman's  books, some\nfrom the own experience and previous attempts.\n\n## Status\n\nThe current status of the library is under heavy development / experimental.\n\nIt is being used in some internal projects, evolving along with them.\n\nThe current implementation has a simple and basic SQLite backend for the DAL.\n\nSee the cases below.\n\n## Introduction\n\nThe basic idea is to hide the complexity of working with different data storages like key-value\ndatabases or relational databases or CAS-storages or other sort of storages behind the minimalistic\nset of interfaces, without taking care of the specific of the concrete data storage, like\nrelational databases.\n\nThe minimal stored data item has to have an identity or primary key and a possibility to be\nstored/loaded. This is pretty enough for a lot of cases, cause all other features may be\nimpemented on top of store/load primitives:\n\n```haskell\nclass HasKey a where\n  data KeyOf a :: *\n  key   :: a -\u003e KeyOf a\n  ns    :: NS a\n\nclass (Monad m, HasKey a) =\u003e SourceStore a m e where\n  store :: e -\u003e a -\u003e m (KeyOf a)\n  load :: e -\u003e KeyOf a -\u003e m (Maybe a)\n```\n\nI.e. indexes and sets may be implemented as a Haskell collections of values,\nand may be stored/loaded as far as those values fit the memory.\n\nTo make the moment of the memory exhaustion happen later, there is the ```HashRef```\nabstraction that represents the hash-addressed object, that may be in fully-loaded\nstate or in unloaded state (in this case it's just a cryptographic hash of the\nreferenced value).\n\n```haskell\nnewtype HashRef (ns :: Symbol) a = HashRef (Either B58 a)\n                                   deriving(Eq,Ord,Show,Data,Generic)\n```\n\nThus, to make the data value storable, you merely have to specify the HashRef type for it and the\ninstance of Store typeclass, for an instance:\n\n```haskell\ntype HashedInt = HashRef \"ints\" Int\ninstance Store HashedInt\n\n-- ...\n\nwithEngine optInMemory $ \\eng -\u003e do\n\n\treplicateM_ 1000 $ do\n\t  ivalues \u003c- generate arbitrary :: IO [Int]\n\t  forM_ ivalues $ \\i -\u003e do\n\t\tk \u003c- store @HashedInt eng (hashRefPack i)\n\t\tii \u003c- load @HashedInt eng k\n\t\tJust i `shouldBe` (fromJust $ hashRefUnpack \u003c$\u003e ii)\n\n```\n\nSo far, we have the minimal set of the primitives that covers a significant\npart of the persistent data use cases.\n\n## TODO\n\n  - Implement abstraction for querying the data\n  - Make it suitable to work with relational databases, including\n    complex queries, relations, indexes, etc.\n\n\n## Cases\n\n### General\n\n```haskell\n\ndata SomeData = SomeData Word32 Word32\n                deriving (Eq,Ord,Show,Data,Generic)\n\n-- HaskKey means that the data item has, at least\n-- a primary key and *namespace*.\n-- The primary key is a primary key,\n-- namespace in case of a relational database means\n-- a table, in a case of any other kind of storage\n-- it could mean \"bag\" or the namespace. I.e. it's a set\n-- of all values of the given type.\n-- Namespace is required to provide a possibility\n-- to enumerate all items of the given type.\n\ninstance HasKey SomeData where\n\n  newtype KeyOf SomeData = SomeDataKey Word32\n                           deriving (Eq,Ord,Show,Generic,Store)\n\n  key (SomeData a _) = SomeDataKey a\n  ns = \"somedata\"\n\n-- ...\n\nreplicateM 1000 $ do\n\twithEngine optInMemory $ \\eng -\u003e do\n\n\t  els  \u003c- Map.fromList \u003c$\u003e generate arbitrary :: IO (Map Word32 Word32)\n\t  let vals  = [ SomeData k v | (k,v) \u003c- Map.toList els ]\n\t  mapM (store eng) vals\n\t  vals2 \u003c- listAll @SomeData eng\n\n\t  vals2 `shouldMatchList` vals\n\n```\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhexresearch%2Fmicro-dal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhexresearch%2Fmicro-dal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhexresearch%2Fmicro-dal/lists"}