{"id":15010664,"url":"https://github.com/verberktstan/swark","last_synced_at":"2025-04-09T18:34:28.221Z","repository":{"id":218115091,"uuid":"745640196","full_name":"verberktstan/swark","owner":"verberktstan","description":"SWiss ARmy Knife - Your everyday clojure toolbelt!","archived":false,"fork":false,"pushed_at":"2024-03-26T05:45:57.000Z","size":13151,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-03-26T06:29:19.418Z","etag":null,"topics":["clojure","clojurescript","utility-library"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/verberktstan.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,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-01-19T19:16:14.000Z","updated_at":"2024-05-29T14:00:18.736Z","dependencies_parsed_at":"2024-03-26T06:28:34.069Z","dependency_job_id":"e76bf8c2-48f6-459c-8e73-8f16819f0d40","html_url":"https://github.com/verberktstan/swark","commit_stats":null,"previous_names":["verberktstan/swark"],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/verberktstan%2Fswark","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/verberktstan%2Fswark/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/verberktstan%2Fswark/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/verberktstan%2Fswark/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/verberktstan","download_url":"https://codeload.github.com/verberktstan/swark/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248088260,"owners_count":21045671,"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","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":["clojure","clojurescript","utility-library"],"created_at":"2024-09-24T19:35:16.135Z","updated_at":"2025-04-09T18:34:28.195Z","avatar_url":"https://github.com/verberktstan.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Swark\n\nSWiss ARmy Knife - Your everyday clojure toolbelt!\n\n[![Clojars Project](https://img.shields.io/clojars/v/org.clojars.stanv/swark.svg)](https://clojars.org/org.clojars.stanv/swark)\n\nThis library contains functionality that you might need every single day as a happy clojure(script) developer.\nThe aim is to provide composable functions that you can use everyday, but are just not as trivial as `(some (comp #{42} :answer) answers)`.\n\nMost functionality *should* work in both Clojure and Clojurescript.\n\n## Basic usage\n\n### Clojure CLI/deps.edn\n\nAdd this dependency to the :deps map in deps.edn:\n\n```org.clojars.stanv/swark {:mvn/version \"0.1.51\"}```\n\nRequire swark.core in your ns form:\n\n```(:require [swark.core :as swark])```\n\nThen you can use the Swark utility functions:\n\n```(swark/key-by :id [{:id 1} {:id 2}]) =\u003e {1 {:id 1} 2 {:id 2}}```\n\n```(swark/map-vals count {:a [:b :c] :d [:e]}) =\u003e {:a 2 :d 1}```\n\n```(swark/jab / 10 0) =\u003e nil```\n\n## Little tour of Swark utilities\n\n### swark.core\n\n- `key-by`: Returns a map where all items are keyed by the result of calling (f item)\n- `map-vals`: Returns a map where f is applied to all the input map's values.\n- `filter-keys`: Returns a map containing only the map-entries whose key returns logical true when supplied to a predicate fn.\n- `select-namespaced`: Returns a map containing only those map-entries whose key's namespace is equal to the supplied namespace.\n- `jab`: Try and fail silently, returning nil when any kind of error or exception is thrown.\n- `-\u003estr`: Returns input coerced to a (trimmed) string. Support (namesapced) keywords etc.\n- `unid`: Return a unique id string.\n- `-\u003ekeyword`: Returns input coerced to a keyword, replacing whitespace with dashes.\n- `invalid-map?`: Minimalistic spec checker, returns logical true if the input does not respect the spec-map. Spec map is simply a map with predicates as vals.\n- `valid-map?`: Complement of invalid-map?\n- `memoir`: Like memoize, but with flushing. Flush the complete cache, or specific parts.\n\n### swark.authom\n\nAtomic authorization. Generate a token for a map, in conjunction with a password and optional secret. And of course check if it matches.\n\n- `with-token`: Returns a map item with a hashed token in it's metadata.\n- `check`: Checks the password (and optional secret) given a map item.\n- `disclose`: Returns map item with it's token associated with ::authom/token. Useful for serializing the hashed token.\n- `conceal`: Returns the map item with it's token moved to it's metadata. Useful for parsing a persisted record.\n\n### swark.cedric\n\n- `Mem.`: Creates a new instance of the in-memory implementation\n- `Csv.`: Creates a new instance the implementation of the csv backend\n- `make-connection`: Starts an atomic interface connection for a database.\n- `upsert-items`: Creates or updates items in the database\n- `find-by-entity`: Returns one database record found by its entity e.g. `[:user/id 123]`\n- `find-by-primary-key`: Returns database records found by its primary key e.g. `#{:user/id}`\n- `read-items`: Returns all (filtered) records from the database\n- `archive-items`: Marks items as archived\n\n### swark.atomic\n\n- `atomic`: Returns a map with in- and output async channels to provide atomic interactions for side-effecting functionality.\n- `put!`: Puts an instruction on the atomic's input channel, blocks and returns the response.\n- `close!`: Closes the atomic's channels and stops the internal go-loop.\n\n## Example - Integrate swark.authom \u0026 swark.cedric\n\n\u003e Note: Cedric's CSV implementation is currently clj only! In cljs you can actually use the in-memory implementation (see swark.cedric/Mem)\n\nLet's say you want to store a user record, some credentials and check their credentials.\nYou can use swark.cedric for the persistence part, and swark.authom for the authentication part.\n\n1. Let's create/connect to a database via the Csv implementation and store db props related to users.\n\n ```\n(ns my.ns\n    (:require [swark.authom :as authom]\n              [swark.cedric :as cedric]\n              [swark.core   :as swark])\n    (:import [swark.cedric Csv]))\n\n(def DB (cedric/Csv. \"/tmp/db.csv\"))\n(def PROPS (merge authom/CEDRIC-PROPS {:primary-key :user/id}))\n ```\n\n2. Create a new user record with `cedric/upsert-items`:\n\n```\n(def USER (-\u003e DB (cedric/upsert-items PROPS [{:user/name \"Readme User\"}]) first))\n```\n\n3. Store credentials (generated with `authom/with-token`) by upserting the user with `cedric/upsert-items`\n\n```\n(let [user (authom/with-token USER :user/id \"pass\" \"SECRET\")]\n    (cedric/upsert-items DB PROPS [user]))\n```\n\n4. Retrieve the user with `cedric/find-by-primary-key` and check their credentials with `authom/check`:\n\n```\n(let [user (-\u003e DB (cedric/find-by-primary-key #{:user/id} {:where (comp #{\"Readme User\"} :user/name)}) first)]\n    (-\u003e user (authom/check :user/id \"pass\" \"SECRET\") assert))\n```\n\n5. Since the csv file might change in the mean while, it is advised to execute all db actions as an asynchronous transaction. You can make use of `cedric/make-connection` like so:\n```\n(let [{::cedric/keys [transact! close!]} (-\u003e \"/tmp/db.csv\" cedric/Csv. cedric/make-connection)]\n    (transact! cedric/upsert-items {:primary-key :id} [{:test \"data\"} {:more \"testdata\" :something 123}]) ; Returns the upserted items.\n    (transact! cedric/read-items   {}) ; Returns all items read.\n    (close!)) ; Don't forget to close the async connection.\n```\n\n## Tests\n\nRun the tests with `clojure -X:test/run`\n\n## Development\n\nStart a repl simply by running `clojure -M:repl/basic` command in your terminal.\nYou can connect your editor via nrepl afterwards, e.g. from emacs; `cider-connect-clj`\nOr create a repl from your editor, e.g. from emacs; `cider-jack-in-clj`\n\n### Jar creation\n\nCreate an uberjar with `clj -X:uberjar :jar swark-0.1.51.jar`\n\n### Local installation\n\nInstall Swark locally with `clj -X:install`\n\n### Deploy to Clojars\n\n```\nenv CLOJARS_USERNAME=username CLOJARS_PASSWORD=clojars-token clj -X:deploy\n```\n\n## License\n\nSwark by Stan Verberkt is marked with CC0 1.0 Universal \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fverberktstan%2Fswark","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fverberktstan%2Fswark","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fverberktstan%2Fswark/lists"}