(local Compiler (require :sqlog.compiler)) (local sqlite (require :diet-sqlite)) (local {: SQLITE_ROW} (require :diet-sqlite.codes)) (local Sqlog {}) (fn Sqlog.new [self ?dbname] (set self.compiler (Compiler)) (set self.db (sqlite.assert (sqlite.open (or ?dbname ":memory:"))))) (fn Sqlog.deftable [self name ...] (self:execute (self.compiler:deftable name ...))) (fn Sqlog.defrule [self head ...] (self.compiler:defrule head ...)) (fn multi? [analysis] (and analysis (> (length analysis) 0))) (fn Sqlog.compile-sql [self analysis] (if (multi? analysis) (each [_ a (ipairs analysis)] (self:compile-sql a)) (when (= analysis.stmt nil) (let [stmt (sqlite.assert (sqlite.prepare self.db analysis.query))] (sqlite.bind stmt analysis.constants) (set analysis.stmt stmt)))) analysis) (fn Sqlog.execute [self analysis ?collect-results] (if (multi? analysis) (icollect [_ a (ipairs analysis)] (self:execute a ?collect-results)) (do (print "running:" analysis.query (fv analysis.constants)) (self:compile-sql analysis) (sqlite.reset analysis.stmt) (if ?collect-results (let [result []] (while (= SQLITE_ROW (sqlite.step analysis.stmt)) (table.insert result (collect [icol expr (ipairs analysis.selection)] (match expr [:as _ name] name _ icol) (sqlite.column analysis.stmt icol)))) result) (sqlite.step analysis.stmt))))) (fn Sqlog.compile-action [self action] (self:compile-sql (match action [:do & actions] (icollect [_ act (ipairs actions)] (self:compile-action act)) [:!+ & insert] (self.compiler:insert (table.unpack insert)) [:literal] (self.compiler:insert action) [:!- & delete] (self.compiler:delete (table.unpack delete)) [:!= & update] (self.compiler:update (table.unpack update)) _ (error (.. "No such action " (fv action)))))) (fn Sqlog.compile-query [self ...] (self:compile-sql (self.compiler:query ...))) (fn Sqlog.specify [self action ...] (when (not= action nil) (match action [:* & rule] (self:defrule (table.unpack rule)) [:table & params] (self:deftable (table.unpack (icollect [_ param (ipairs params)] (match param [_ name] name)))) [:sql query & constants] (self:execute {: query : constants}) _ (self:execute (self:compile-action action))) (self:specify ...))) (fn Sqlog.query [self ...] (self:execute (self:compile-query ...) true)) (setmetatable Sqlog {:__call (fn [cls ...] (doto (setmetatable {} {:__index cls} ) (: :new ...)))})