Write working function to convert from hash table->SQLite

This commit is contained in:
contrapunctus 2020-11-08 18:04:13 +05:30
parent b141b3b2d1
commit 1f4f018c70
2 changed files with 39 additions and 17 deletions

View File

@ -171,7 +171,7 @@ ppp.el doesn't align plist values along the same column. It's also GPL, and I'm
: (foo (1 . bar))
Yikes!
** chronometrist [8%]
** chronometrist [7%]
1. [ ] Add =:stop= time when we call =chronometrist-kv-accept=, not when we quit the key-value prompt with a blank input.
* It might be nice to be able to quit =chronometrist-kv-add= with C-g instead, actually.
+ =C-g= stops execution of =chronometrist-run-functions-and-clock-in=/=chronometrist-run-functions-and-clock-out=, so they can't reach the calls for =chronometrist-in=/=chronometrist-out=.
@ -201,8 +201,12 @@ ppp.el doesn't align plist values along the same column. It's also GPL, and I'm
11. [ ] Pretty printer - add support for alists as values
12. [ ] key-values - make detection of Lisp values more robust.
* If the input string can be read in a single call to =read=, treat it as an s-expression; else, use the current heuristics.
13. [ ] key-values - create transformer for key-values, to be run before they are added to the file. This will allow users to do cool things like sorting the key-values.
13. [ ] key-values - create transformer for key-values, to be run before they are added to the file. This will allow users to do things like sorting the key-values.
*** Migration [0%]
1. [ ] Implement readers (format -> hash table), emitters (hash table -> format), and predicates for each format. Then implement a single =migrate= command to convert between any supported formats.
* sounds like a job for EIEIO - each format could be defined as an object, with slots for information such as the file extension.
2. [ ] Instead of using =require= for all backends and dependencies, check which backends are loaded, and load dependencies accordingly.
3. [ ] Make migration asynchronous, and use output from the sub-process to make a progress indicator.
** chronometrist-report [0%]
1. [ ] Show week counter and max weeks; don't scroll past first/last weeks
2. [ ] Highlight column of current day

View File

@ -21,7 +21,7 @@
(require 'chronometrist-common)
(require 'chronometrist-time)
(require 'chronometrist-plist-pp)
(require 'emacsql-sqlite)
(require 'emacsql-sqlite3)
(defvar chronometrist-file)
(defvar chronometrist-migrate-table (make-hash-table :test #'equal))
@ -105,7 +105,7 @@ file names respectively."
chronometrist-migrate-table)
(save-buffer)))))
(defvar chronometrist-migrate-db)
(defvar chronometrist-migrate-db (emacsql-sqlite3 (locate-user-emacs-file "chronometrist.sqlite")))
(defun chronometrist-migrate-populate-sexp (in-file)
"Read data from IN-FILE to `chronometrist-migrate-table'.
@ -157,19 +157,37 @@ file names respectively."
:values ([(plist-get :na)])]))
chronometrist-migrate-table)))
(cl-loop for events being the hash-values of chronometrist-events do
(cl-loop for event in events do
(cl-loop for (keyword value) on event by #'cddr do
(let* ((pragma (emacsql db [:pragma (funcall table_info events)]))
(row-exists-p (cl-loop for list in pragma thereis
(eq (--> (symbol-name keyword)
(defun chronometrist-migrate-to-sqlite3 ()
(cl-loop with count = 0
for events being the hash-values of chronometrist-events do
(cl-loop for event in events do
(let* ((keywords (seq-filter #'keywordp event))
(values (seq-remove #'keywordp event))
(columns (mapcar (lambda (keyword)
(--> (symbol-name keyword)
(s-chop-prefix ":" it)
(intern it))
(second list)))))
(unless row-exists-p
(emacsql db [:alter-table events :add-column $i1]) keyword)
;; FIXME
(emacsql db [:insert-into events :values $i1] value)))))
;; emacsql seems to automatically
;; convert dashes in column names
;; to underscores, so we do the
;; same, lest we get a "column
;; already exists" error
(replace-regexp-in-string "-" "_" it)
(intern it)))
keywords)))
;; ensure all keywords in this plist exist as SQL columns
(cl-loop for column in columns do
(let* ((pragma (emacsql chronometrist-migrate-db [:pragma (funcall table_info events)]))
(column-exists (cl-loop for column-spec in pragma thereis
(eq column (second column-spec)))))
(unless column-exists
(emacsql chronometrist-migrate-db [:alter-table events :add-column $i1] column))))
(emacsql chronometrist-migrate-db [:insert-into events [$i1] :values $v2]
(vconcat columns) (vconcat values)))
(incf count)
(when (zerop (% count 5))
(message "chronometrist-migrate-migrate - %s events converted" count)))
finally do
(message "chronometrist-migrate - finished converting %s events." count)))
(defun chronometrist-migrate (input-format output-format &optional input-file output-file)
"Migrate a Chronometrist file from INPUT-FORMAT to OUTPUT-FORMAT.