{"id":13529298,"url":"https://github.com/mmaul/cl-influxdb","last_synced_at":"2026-03-02T23:36:29.753Z","repository":{"id":15083321,"uuid":"17809771","full_name":"mmaul/cl-influxdb","owner":"mmaul","description":"Common Lisp interface to the Time Series Database InfluxDB","archived":false,"fork":false,"pushed_at":"2017-03-15T03:12:18.000Z","size":481,"stargazers_count":24,"open_issues_count":1,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-01-11T17:53:02.029Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mmaul.png","metadata":{"files":{"readme":"README-v8.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":"2014-03-16T21:34:06.000Z","updated_at":"2025-04-26T14:42:26.000Z","dependencies_parsed_at":"2022-08-30T09:51:40.677Z","dependency_job_id":null,"html_url":"https://github.com/mmaul/cl-influxdb","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mmaul/cl-influxdb","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmaul%2Fcl-influxdb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmaul%2Fcl-influxdb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmaul%2Fcl-influxdb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmaul%2Fcl-influxdb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mmaul","download_url":"https://codeload.github.com/mmaul/cl-influxdb/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmaul%2Fcl-influxdb/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30025133,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-02T23:31:36.176Z","status":"ssl_error","status_checked_at":"2026-03-02T23:31:20.819Z","response_time":60,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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-08-01T07:00:35.132Z","updated_at":"2026-03-02T23:36:29.720Z","avatar_url":"https://github.com/mmaul.png","language":"Common Lisp","funding_links":[],"categories":["Client libraries"],"sub_categories":["Unofficial"],"readme":"CL-INFLUXDB\n-----------\n\nThis package is a native Common Lisp interface for the InfluxDB time series database.\n\n[InfluxDB](http://influxdb.org) is a scalable time series database.\n\nInstallation\n------------\ncl-influxdb will be distributed via [Quicklisp](http://quicklisp.ort).\nIt can also be obtained via it's [github repository] (http://github.com/mmaul/cl-influxdb)\n\nUnder SBCL the system cl-influxdb.tests is excluded to to incompatibilities with NST and \nSBCL's enforcement of *pprint-dispatch* immutability.\n\n\n===========================================================================\n\nUsage\n=====\n\nLets create a instance of class INFLUXDB to get started the default is\nuser = root, password = root, host = 127.0.0.1, port = 8086.\n\n```\n;;-----------------------------------CODE----------------------------------\n(SETQ *INFLUXDB* (MAKE-INSTANCE 'INFLUXDB :DATABASE *DB*))\n;;-------------------------------------------------------------------------\n\nResults:\n\n#\u003cINFLUXDB #x302003474EFD\u003e\n```\n===========================================================================\n\nCreating another instance if INFLUX DB to test database user commands later.\n\n```\n;;-----------------------------------CODE----------------------------------\n(SETQ *USER-DB*\n      (MAKE-INSTANCE\n        'INFLUXDB\n        :DATABASE\n        *DB*\n        :USER\n        *APP-USER*\n        :PASSWORD\n        *APP-PASSWORD*))\n;;-------------------------------------------------------------------------\n\nResults:\n\n#\u003cINFLUXDB #x3020034744DD\u003e\n```\n===========================================================================\n\nFirst lets see if the server is alive\n\n```\n;;-----------------------------------CODE----------------------------------\n(PING *INFLUXDB*)\n;;-------------------------------------------------------------------------\n\nResults:\n\n((:STATUS . \"ok\"))\n```\n===========================================================================\n\nGet list of defined databases and check to see if example database \n'example' exists.  If it does delete it.\n\n```\n;;-----------------------------------CODE----------------------------------\n(LOOP FOR (NAME RESP) IN (GET-DATABASE-LIST *INFLUXDB*)\n      DO (FORMAT T \"~t ~a~%\" (CDR NAME))\n      WHEN (STRING= *DB* (CDR NAME))\n        DO (PROGN (FORMAT T \"Deleting: ~a~%\" (CDR NAME))\n                  (DELETE-DATABASE *INFLUXDB* (CDR NAME))))\n;;-------------------------------------------------------------------------\n  example\nDeleting: example\n\nResults:\n\nNIL\n```\n===========================================================================\n\nCreate a new database\n```\n;;-----------------------------------CODE----------------------------------\n(HANDLER-CASE (CREATE-DATABASE *INFLUXDB* *DB*) (COMMAND-FAIL (E) E))\n;;-------------------------------------------------------------------------\n\nResults:\n\nT\n```\n===========================================================================\n \nIf we had tried to create a database and it already existed\nWe get a condition, like this:\n```\n;;-----------------------------------CODE----------------------------------\n(HANDLER-CASE (CREATE-DATABASE *INFLUXDB* *DB*)\n              (COMMAND-FAIL (E) (PRINT E)))\n;;-------------------------------------------------------------------------\n\n#\u003cCOMMAND-FAIL #x3020034AC29D\u003e \nResults:\n\n#\u003cCOMMAND-FAIL #x3020034AC29D\u003e\n```\n===========================================================================\n\nNot that it's necessary for this simple test, but you might need\nto create a seperate user for an application. lets add the user 'user'\n```\n;;-----------------------------------CODE----------------------------------\n(ADD-DATABASE-USER *INFLUXDB* *APP-USER* *APP-PASSWORD*)\n;;-------------------------------------------------------------------------\n\nResults:\n\nT\n```\n===========================================================================\n\nLets change the app user password\n```\n;;-----------------------------------CODE----------------------------------\n(UPDATE-DATABASE-USER-PASSWORD *USER-DB* \"newpass1\")\n;;-------------------------------------------------------------------------\n\nResults:\n\nT\n```\n===========================================================================\n \nLoad some data Note that all commands\n```\n;;-----------------------------------CODE----------------------------------\n(WRITE-POINTS *USER-DB*\n              '(((:NAME . RESPONSE_TIMES) (:COLUMNS TIME VALUE)\n                 (:POINTS (1394761721 1.0) (1394761722 2.0))))\n              :TIME-PRECISION\n              'S)\n;;-------------------------------------------------------------------------\n\nResults:\n\nT\n```\n===========================================================================\n\nNow that we inserted some data lets list it.\n\n```\n;;-----------------------------------CODE----------------------------------\n(QUERY *USER-DB* \"select time from response_times;\")\n;;-------------------------------------------------------------------------\n\nResults:\n\n(((:NAME . \"response_times\")\n  (:COLUMNS \"time\" \"sequence_number\" \"value\")\n  (:POINTS (1394761 260001 2) (1394761 250001 1))))\n```\n===========================================================================\n\nLets insert some data dynamically for a data source on the web.\nOne thing to note is that when using symbols or keywords, is that they\n are down cased. So a series :MySeries will be created as 'myseries'\n\n```\n;;-----------------------------------CODE----------------------------------\n(WRITE-POINTS *INFLUXDB*\n              (LIST (LIST* '(:NAME . GASRATECO2)\n                           (LIST* '(:COLUMNS INPUTGASRATE CO2)\n                                  (LIST\n                                   (CONS\n                                    :POINTS\n                                    (MAPCAR\n                                     (LAMBDA\n                                      (L)\n                                      (MAPCAR\n                                       #'ORG.MAPCAR.PARSE-NUMBER:PARSE-NUMBER\n                                       (SPLIT-SEQUENCE:SPLIT-SEQUENCE\n                                        #\\,\n                                        L)))\n                                     (CDR\n                                      (SPLIT-SEQUENCE:SPLIT-SEQUENCE\n                                       #\\Newline\n                                       (DRAKMA:HTTP-REQUEST\n                                        \"http://datasets.connectmv.com/file/gas-furnace.csv\")))))))))\n              :TIME-PRECISION\n              'S)\n;;-------------------------------------------------------------------------\n\nResults:\n\nT\n```\n===========================================================================\n\nLets try a group by query...\n\n```\n;;-----------------------------------CODE----------------------------------\n(QUERY *INFLUXDB*\n       \"select max(inputgasrate/co2) from gasrateco2 group by time(160m);\")\n;;-------------------------------------------------------------------------\n\nResults:\n\n(((:NAME . \"gasrateco2\") (:COLUMNS \"time\" \"max\")\n  (:POINTS (1395196800 0.05624))))\n```\n===========================================================================\n\nNow for continous queries, generally these are used for precomputed rollups.\nLets list the current precomputed queries.\n\n```\n;;-----------------------------------CODE----------------------------------\n(LIST-CONTINUOUS-QUERIES *INFLUXDB*)\n;;-------------------------------------------------------------------------\n\nResults:\n\n(((:ID . 1)\n  (:QUERY\n   . \"select mean(inputgasrate), mean(co2) from gasrateco2 group by time(1h) into gasrateco2.1h;\"))\n)\n```\n===========================================================================\n\nNow to create a continous query, \n\n\n```\n;;-----------------------------------CODE----------------------------------\n(CREATE-CONTINUOUS-QUERIES\n  *INFLUXDB*\n  \"select mean(inputgasrate), mean(co2) from gasrateco2 group by time(1h) into gasrateco2.1h;\")\n;;-------------------------------------------------------------------------\n\nResults:\n\nT\n```\n===========================================================================\n\nLets clean up now.\n\nDeleting database user 'user'\n\n```\n;;-----------------------------------CODE----------------------------------\n(DELETE-DATABASE-USER *INFLUXDB* *APP-USER*)\n;;-------------------------------------------------------------------------\n\nResults:\n\nT\n```\n===========================================================================\n\nDeleting series response_times\n\n```\n;;-----------------------------------CODE----------------------------------\n(DELETE-SERIES *INFLUXDB* :RESPONSE_TIMES)\n;;-------------------------------------------------------------------------\n\nResults:\n\nT\n```\n===========================================================================\n\nDeleting series gasrateco2\n\n```\n;;-----------------------------------CODE----------------------------------\n(DELETE-SERIES *INFLUXDB* :GASRATECO2)\n;;-------------------------------------------------------------------------\n\nResults:\n\nT\n```\n===========================================================================\n\nLets see what shards exist...\n\n```\n;;-----------------------------------CODE----------------------------------\n(GET-SHARDS *INFLUXDB*)\n;;-------------------------------------------------------------------------\n\nResults:\n\n((:LONG-TERM)\n (:SHORT-TERM\n  ((:END-TIME . 1395273600) (:ID . 1) (:SERVER-IDS 1)\n   (:START-TIME . 1394668800))\n  ((:END-TIME . 1814400) (:ID . 2) (:SERVER-IDS 1)\n   (:START-TIME . 1209600))))\n```\n===========================================================================\n\nAsyncronous Usage\n=================\n\nRather that create an async query mechanism or write wrappers we will\njust just lparallel ought right. It is simpler and more elegant.\n\nFirst we just need to create a lparallel kernel which maintains a\nthread pool. The integer parameter to make-kernel specifies the number\nof CPU cores available to lparallel\n\n```\n;;-----------------------------------CODE----------------------------------\n(WHEN (NOT LPARALLEL.KERNEL:*KERNEL*)\n  (SETF LPARALLEL.KERNEL:*KERNEL* (LPARALLEL.KERNEL:MAKE-KERNEL 2)))\n;;-------------------------------------------------------------------------\n\nResults:\n\nNIL\n```\n===========================================================================\n\nCreate a new database 'example-async unless it already exists\n```\n;;-----------------------------------CODE----------------------------------\n(HANDLER-CASE (CREATE-DATABASE\n                CL-INFLUXDB.EXAMPLES-ASYNC::*INFLUXDB*\n                CL-INFLUXDB.EXAMPLES-ASYNC::*DB*)\n              (COMMAND-FAIL (CL-INFLUXDB.EXAMPLES-ASYNC::E)\n               (PRINT CL-INFLUXDB.EXAMPLES-ASYNC::E)))\n;;-------------------------------------------------------------------------\n\nResults:\n\nT\n```\n===========================================================================\n \nRepeating the bulk load from prefious examples, we use lparallel futures to preform the operation asynchronously.\n\nThe pattern is: \n* Make a promise\n* Make future form that fuflills promise\n* Wait and/or do something else \n* Check for the fulfillment to be complete or call force which blocks\n\nFor example something that waits 10 seconds for a future to complete then forces it.\n```\n  (let ((p (promise))) \n    (future (progn (sleep .3) (fulfill p 'done)))\n    (format t \"Wait for future to come\") \n    (loop for i from 1 to 10 \n      when (not (fulfilledp p)) do \n        (progn (print i) (sleep .1)))\n    (force p))\n```\nGet it? On to using this pattern with write-points\n\n```\n;;-----------------------------------CODE----------------------------------\n(LET ((CL-INFLUXDB.EXAMPLES-ASYNC::P (LPARALLEL.PROMISE:PROMISE)))\n  (LPARALLEL.PROMISE:FUTURE (LET ((CL-INFLUXDB.EXAMPLES-ASYNC::RESULT\n                                   (WRITE-POINTS\n                                    CL-INFLUXDB.EXAMPLES-ASYNC::*INFLUXDB*\n                                    (LIST\n                                     (LIST*\n                                      '(:NAME\n                                        . CL-INFLUXDB.EXAMPLES-ASYNC::GASRATECO2)\n                                      (LIST*\n                                       '(:COLUMNS\n                                         CL-INFLUXDB.EXAMPLES-ASYNC::INPUTGASRATE\n                                         CL-INFLUXDB.EXAMPLES-ASYNC::CO2)\n                                       (LIST\n                                        (CONS\n                                         :POINTS\n                                         (DATA-TABLE:ROWS\n                                          (CL-CSV:GET-DATA-TABLE-FROM-CSV\n                                           (DRAKMA:HTTP-REQUEST\n                                            \"http://datasets.connectmv.com/file/gas-furnace.csv\"\n                                            :WANT-STREAM\n                                            T))))))))\n                                    :TIME-PRECISION\n                                    'CL-INFLUXDB.EXAMPLES-ASYNC::S)))\n                              (LPARALLEL.PROMISE:FULFILL\n                               CL-INFLUXDB.EXAMPLES-ASYNC::P\n                               CL-INFLUXDB.EXAMPLES-ASYNC::RESULT)))\n  (FORMAT T \"Right, lets sleep for a second...~%\")\n  (SLEEP 1)\n  (IF (LPARALLEL.PROMISE:FULFILLEDP CL-INFLUXDB.EXAMPLES-ASYNC::P)\n      (FORMAT T \"Looks like it's done~%\")\n      (FORMAT T\n              \"Looks like it's not done yet. Well we will force it, then~%\"))\n  (PRINT (LPARALLEL.PROMISE:FORCE CL-INFLUXDB.EXAMPLES-ASYNC::P)))\n;;-------------------------------------------------------------------------\nRight, lets sleep for a second...\nLooks like it's done\n\nT \nResults:\n\nT\n```\n===========================================================================\n\nLets try a group by query...asynchronously\nWe will request fulfillment wait up to 10 seconds and the get the results\n\n```\n;;-----------------------------------CODE----------------------------------\n(LET ((CL-INFLUXDB.EXAMPLES-ASYNC::P (LPARALLEL.PROMISE:PROMISE)))\n  (LPARALLEL.PROMISE:FUTURE (LPARALLEL.PROMISE:FULFILL CL-INFLUXDB.EXAMPLES-ASYNC::P\n                                                       (QUERY\n                                                        CL-INFLUXDB.EXAMPLES-ASYNC::*INFLUXDB*\n                                                        \"select max(inputgasrate/co2) from gasrateco2 group by time(160m);\")))\n  (LOOP CL-INFLUXDB.EXAMPLES-ASYNC::FOR CL-INFLUXDB.EXAMPLES-ASYNC::I\n                                        CL-INFLUXDB.EXAMPLES-ASYNC::FROM\n                                        1\n                                        CL-INFLUXDB.EXAMPLES-ASYNC::TO\n                                        1000\n        WHEN (NOT (LPARALLEL.PROMISE:FULFILLEDP CL-INFLUXDB.EXAMPLES-ASYNC::P))\n          DO (PROGN (FORMAT T\n                            \"Wait ~fms~%\"\n                            (/ CL-INFLUXDB.EXAMPLES-ASYNC::I 100))\n                    (SLEEP 0.01)))\n          (LPARALLEL.PROMISE:FORCE CL-INFLUXDB.EXAMPLES-ASYNC::P))\n;;-------------------------------------------------------------------------\nWait 0.01ms\nWait 0.02ms\nWait 0.03ms\n\nResults:\n\n(((:NAME . \"gasrateco2\") (:COLUMNS \"time\" \"max\")\n  (:POINTS (1395196800 0.05624))))\n```\n===========================================================================\n\nRemove the new database 'example-async\n```\n;;-----------------------------------CODE----------------------------------\n(HANDLER-CASE (DELETE-DATABASE\n                CL-INFLUXDB.EXAMPLES-ASYNC::*INFLUXDB*\n                CL-INFLUXDB.EXAMPLES-ASYNC::*DB*)\n              (COMMAND-FAIL (CL-INFLUXDB.EXAMPLES-ASYNC::E)\n               (PRINT CL-INFLUXDB.EXAMPLES-ASYNC::E)))\n;;-------------------------------------------------------------------------\n\nResults:\n\nT\n```\nLICENSE\n=======\nThe MIT License (MIT)\n\nCopyright (c) 2014 Michael Maul\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmmaul%2Fcl-influxdb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmmaul%2Fcl-influxdb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmmaul%2Fcl-influxdb/lists"}