{"id":16866973,"url":"https://github.com/webern/moneybags","last_synced_at":"2025-08-10T19:21:58.759Z","repository":{"id":43214414,"uuid":"466558556","full_name":"webern/moneybags","owner":"webern","description":"A take-home assignment","archived":false,"fork":false,"pushed_at":"2022-03-13T06:29:15.000Z","size":26,"stargazers_count":2,"open_issues_count":3,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-05T11:41:45.210Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/webern.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-03-05T20:16:27.000Z","updated_at":"2023-03-08T16:23:19.000Z","dependencies_parsed_at":"2022-08-29T22:22:13.490Z","dependency_job_id":null,"html_url":"https://github.com/webern/moneybags","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/webern/moneybags","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webern%2Fmoneybags","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webern%2Fmoneybags/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webern%2Fmoneybags/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webern%2Fmoneybags/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/webern","download_url":"https://codeload.github.com/webern/moneybags/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webern%2Fmoneybags/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267569578,"owners_count":24109107,"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-10-13T14:52:17.396Z","updated_at":"2025-07-28T19:08:12.077Z","avatar_url":"https://github.com/webern.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# Moneybags\n\nThis program was written for a take-home assignment and has no value for any other purpose.\n\n## Usage\n\nTakes a CSV file as input, process the transactions described therein, and outputs a CSV file to `stdout` representing\nthe resultant account balances.\n\nExample: `moneybags transactions.csv \u003e accounts.csv`\n\nInput format looks like this:\n\n```csv\ntype,client,tx,amount\ndeposit,1,1,1.0\ndeposit,2,2,2.0\ndeposit,1,3,2.0\nwithdrawal,1,4,1.5\nwithdrawal,2,5,3.0\n```\n\nOutput format looks like this:\n\n```csv\nclient,available,held,total,locked\n1,1.5,0.0,1.5,false\n2,2.0,0.0,2.0,false\n```\n\nSpecifications for the input, output and behavior were provided and are not repeated here.\nThese specifications are relatively simple and can be deduced from reading the code easily enough.\n\n## Development\n\nThe normal cargo commands should work fine: `cargo build`, `cargo test`, etc.\nContinuous integration checks formatting, tests, build, install and clippy linting in strict mode.\n\nTo do the same checks locally, run `make check`.\n\n## Discussion\n\n### Correctness\n\nThere are cases in the code where the specification may be unclear on desired program behavior.\nI have created follow-up GitHub issues for each of these, listed here,\nand linked to them in the codebase at their approximate locations.\n- [dispute, resolve and chargeback transactions have no IDs](https://github.com/webern/moneybags/issues/2)\n- [define min and max values for amount and client id types](https://github.com/webern/moneybags/issues/3)\n- [transactions on a frozen account](https://github.com/webern/moneybags/issues/4)\n- [can both deposit and withdrawal transactions be disputed?](https://github.com/webern/moneybags/issues/5)\n\nEdit: more questions...\n- What should we do if the client ID of a Chargeback, Resolve or Dispute does not match the client ID of the original \n  record? Error? (We print an error and do not process it.)\n- What should we do if a Chargeback or Resolve does not have a corresponding Dispute? (Not handled.)\n\n\u003e For the cases you are handling are you handling them correctly?\n\nProbably?\nFor this I tried to make sure I followed the spec's directions carefully.\nI have clarifying questions listed above.\n\n\u003e Did you test against sample data?\n\nI added some sample data and integration tests to `tests` directory.\n\n\u003e Did you write unit tests for the complicated bits?\n\nYes, I added some unit tests for parsing and record processing.\nI wrote integration tests for the end-to-end CSV-in, CSV-out workflow.\n\n\u003e Are you doing something dangerous? Tell us why you chose to do it this way\n\nTypes are not checked for wrapping when adding and subtracting.\nThese could panic if wrapping occurs.\nI did it this way for lack of time.\nIn critical code we would check for wrapping values and return an error instead.\n\nThe implementation is not thread safe because there is only one thread.\nAs such, the implementation does not hold a transaction on the imaginary database.\nThis is called out in a comment.\n\n\u003e Can you stream values through memory as opposed to loading the entire data set upfront?\n\nDuring parsing the data is streamed through Serde, but each deserialized value is being loaded in memory.\nWe are doing it this way because rows of data can reference other rows of data with no way to know which rows may become\n\"referenced\".\n\n## Maintainability\n\n- The code uses flexible input types to facilitate testing.\n- The `main` function does very little other than call a function that is itself test-able.\n- The code is documented.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebern%2Fmoneybags","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebern%2Fmoneybags","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebern%2Fmoneybags/lists"}