From 021bb3c700e40df1a5c431c6cb470e4709899c71 Mon Sep 17 00:00:00 2001 From: Kinneyzhang Date: Tue, 25 Aug 2026 17:16:57 +0800 Subject: [PATCH] feat: return normalized mutation results --- etaf-sqlite.el | 24 ++++++++++++++++++++---- tests/etaf-sqlite-tests.el | 8 ++++++-- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/etaf-sqlite.el b/etaf-sqlite.el index 4a07abd..b54d71c 100644 --- a/etaf-sqlite.el +++ b/etaf-sqlite.el @@ -299,6 +299,17 @@ validated once and never comes from a runtime query." (and (listp payload) (assoc key payload)))) (push (cons column (etaf-sqlite--record-value payload key)) result)))))) +(defun etaf-sqlite--mutation-result (connection operation value) + "Return a normalized mutation result for OPERATION and VALUE from CONNECTION. + +The result keeps source-specific details behind the Data contract while +exposing the inserted identity and affected row count to application code." + (list :operation operation + :id (when (eq operation 'insert) + (caar (sqlite-select connection "SELECT last_insert_rowid()"))) + :changes (caar (sqlite-select connection "SELECT changes()")) + :value value)) + (defun etaf-sqlite--mutate (database operation payload) "Apply one Data mutation OPERATION with PAYLOAD to DATABASE." (let* ((table (etaf-sqlite--database-table database)) @@ -314,7 +325,8 @@ validated once and never comes from a runtime query." (etaf-sqlite--transaction connection (lambda (transaction-connection) - (pcase operation + (let ((value + (pcase operation ('insert (let* ((columns (cl-remove-if @@ -391,15 +403,19 @@ validated once and never comes from a runtime query." (_ (signal 'etaf-sqlite-error (list (format "Unsupported SQLite mutation: %S" - operation))))))))))) + operation))))))) + (etaf-sqlite--mutation-result + transaction-connection operation value)))))))) ;;;###autoload (defun etaf-sqlite-source (database) "Return an `etaf-data-source' backed by DATABASE. The source accepts equality plist/alist queries and supports `insert', -`replace', `update', and `delete' mutations. Every operation uses a short -connection; controllers remain the owner of reactive state and lifecycle." +`replace', `update', and `delete' mutations. Mutation results include the +operation, affected row count, and inserted identity when applicable. Every +operation uses a short connection; controllers remain the owner of reactive +state and lifecycle." (unless (etaf-sqlite--database-p database) (signal 'wrong-type-argument (list 'etaf-sqlite-database-p database))) diff --git a/tests/etaf-sqlite-tests.el b/tests/etaf-sqlite-tests.el index c4fc048..1620ef6 100644 --- a/tests/etaf-sqlite-tests.el +++ b/tests/etaf-sqlite-tests.el @@ -60,8 +60,12 @@ :page-size 20 :auto-load t))) (unwind-protect (progn - (etaf-data-mutate controller 'insert - '(:id 3 :name "Alan" :score 30)) + (let ((result (etaf-data-mutate + controller 'insert + '(:id 3 :name "Alan" :score 30)))) + (should (equal 'insert (plist-get result :operation))) + (should (= 3 (plist-get result :id))) + (should (= 1 (plist-get result :changes)))) (should (= (etaf-value (etaf-data-total controller)) 3)) (etaf-data-mutate controller 'update '(:id 3 :name "Alan Turing" :score 31))