diff --git a/src/lua/cache.lua b/src/lua/cache.lua
index 2f79e0d..86e5e3f 100644
--- a/src/lua/cache.lua
+++ b/src/lua/cache.lua
@@ -1,8 +1,11 @@
---[[
-Implements a simple in-memory cache. The cache has no upper size limit, and
-may cause out-of-memory errors. When this happens, the OS will kill the kore
-worker process, and the kore parent process will restart with a fresh, empty
-cache
+--[[ md
+
+@name lua/cache
+
+Implements a simple in memory read through cache.
+The cache has no upper size limit, and may cause out-of-memory errors.
+When this happens, the OS will kill the kore worker process,
+and the kore parent process will restart with a fresh, empty cache.
]]
local sql = require("lsqlite3")
@@ -15,6 +18,68 @@ local ret = {}
local stmnt_cache, stmnt_insert_cache, stmnt_dirty_cache
+--[[ cat
+@name lua/cache
+
Schema for Cache
+The cache mechanism is a in-memeory sqlite3 database behind the scenes, it
+can ensure consistency and atomic updates & dirtying, though it doesn't today.
+
+ cache
+
+ Attributes |
+ Field |
+ Type |
+ Description |
+
+
+ Primary Key |
+ path |
+ TEXT |
+
+ The logical path this text was rendered at,
+ before browser-specific headers (like accept-encoding)
+ are applied
+ |
+
+
+ |
+ data |
+ BLOB |
+
+ The returned result from the function passed into
+ cache.render(), the result must be a string, and
+ may contain nulls.
+ |
+
+
+ |
+ updated |
+ INTEGER |
+
+ The time this item was rendered at, can be used to set
+ a minimum update frequency. This is used so that web
+ scrapers don't constantly trigger re-renders of the
+ index page.
+ |
+
+
+ |
+ dirty |
+ INTEGER |
+
+ Does this page need to be re-rendered the next time it
+ is called? For example, an author's story could have
+ multiple hits, which would require rerendering their
+ author page to show the new hit count, but we don't
+ actually need to do it until someone requests the
+ author page. In this case, we keep the old page around
+ to save time trying to clear it and potentially hit
+ sqlite's garbage collector.
+ |
+
+
+]]
+
local oldconfigure = configure
function configure(...)
ret.cache = db.sqlassert(sql.open_memory())-- Expose db for testing
@@ -52,7 +117,40 @@ function configure(...)
return oldconfigure(...)
end
---Render a page, with cacheing. If you need to dirty a cache, call dirty_cache()
+--[[ md
+@name lua/cache
+
+### cache.render
+
+Render a page with cacheing.
+The callback will be called with no arguments, and must return a string.
+
+Parameters:
+
+0. pagename - {{lua/string}} - A logical string to associate with this
+rendered page, this must be passed exactly into render() in order
+to (potentially) retrive the cached page.
+0. callback - {{lua/function}} - A function that may be called,
+if it is called, it is called with no arguments, and must return a string.
+The returned string may have embedded nulls.
+
+Returns:
+
+0. {{lua/string}} - Either the return of the passed function, or the cached
+string.
+
+Example:
+
+ cache = require("cache")
+ func = function()
+ print("Called")
+ return "Hello, world!"
+ end
+ print(cache.render("/test",func)) -- prints "Called", then "Hello, world!"
+ print(cache.render("/test",func)) -- prints "Hello, world!"
+ print(cache.render("/test",func)) -- prints "Hello, world!"
+
+]]
function ret.render(pagename,callback)
stmnt_cache:bind_names{path=pagename}
local err = db.do_sql(stmnt_cache)
@@ -81,8 +179,37 @@ function ret.render(pagename,callback)
return text
end
--- Dirty a cached page, causing it to be re-rendered the next time it's
--- requested. Doesn't actually delete it or anything, just sets it's dirty bit
+--[[ md
+@name lua/cache
+
+### cache.dirty
+
+Dirty a cached page, causing it to be re-rendered the next time it's
+requested. Doesn't actually delete it or free memory, just sets its dirty bit.
+If the page does not exists or has not been rendered yet, this function does
+not error.
+
+Parameters:
+
+0. url - {{lua/string}} - `pagename` from the render function, the logical
+string associcated with this rendered page.
+
+No returns
+
+Example:
+
+ cache = require("cache")
+ func = function()
+ print("Called")
+ return "Hello, world!"
+ end
+ print(cache.render("/test",func)) -- prints "Called", then "Hello, world!"
+ print(cache.render("/test",func)) -- prints "Hello, world!")
+ cache.dirty("/test")
+ print(cache.render("/test",func)) -- prints "Called", then "Hello, world!"
+ print(cache.render("/test",func)) -- prints "Hello, world!"
+]]
+
function ret.dirty(url)
stmnt_dirty_cache:bind_names{
path = url
diff --git a/src/lua/db.lua b/src/lua/db.lua
index 9592997..6b5a322 100644
--- a/src/lua/db.lua
+++ b/src/lua/db.lua
@@ -1,6 +1,10 @@
--[[ md
@name lua/db
+
+## Overview
+
Does most of the database interaction.
+Creates default empty database during configure()
Notably, holds a connection to the open sqlite3 database in .conn
]]
local sql = require("lsqlite3")
@@ -11,7 +15,9 @@ local config = require("config")
local db = {}
--[[ md
-@name lua/db/sqlassert
+@name lua/db
+
+### db.sqlassert
Runs an sql query and receives the 3 arguments back, prints a nice error
message on fail, and returns true on success.
@@ -36,8 +42,8 @@ that error checking and assignment can all be done on a single line.
Example:
-> db = require("db")
-> query = db.sqlassert(db.conn:parepare("SELECT 'Hello, world!'"))
+ db = require("db")
+ query = db.sqlassert(db.conn:parepare("SELECT 'Hello, world!'"))
]]
function db.sqlassert(r, errcode, err)
if not r then
@@ -51,7 +57,9 @@ function db.sqlassert(r, errcode, err)
end
--[[ md
-@name lua/db/do_sql
+@name lua/db
+
+### db.do_sql
Continuously tries to perform an sql statement until it goes through. This function may call {{lua/coroutine/yield}}
@@ -65,12 +73,12 @@ Returns:
Example:
-> sql = require("lsqlite3")
-> configure = function(...) end -- Mock smr environment
-> db = require("db")
-> configure()
-> query = db.conn:prepare("SELECT 'Hello, world!';")
-> assert(db.do_sql(query))
+ sql = require("lsqlite3")
+ configure = function(...) end -- Mock smr environment
+ db = require("db")
+ configure()
+ query = db.conn:prepare("SELECT 'Hello, world!';")
+ assert(db.do_sql(query))
]]
function db.do_sql(stmnt)
if not stmnt then error("No statement",2) end
@@ -88,7 +96,9 @@ function db.do_sql(stmnt)
end
--[[ md
-@name lua/db/sql_rows
+@name lua/db
+
+### db.sql_rows
Provides an iterator that loops over results in an sql statement or throws an
error, then resets the statement after the loop is done.
@@ -107,12 +117,11 @@ Returns:
Example:
-> db = require("db")
-> query = db.conn:prepare("SELECT 'Hello, world!';")
-> for row in db.sql_rows(query) do
-> print(row)
-> end
-Hello, world!
+ db = require("db")
+ query = db.conn:prepare("SELECT 'Hello, world!';")
+ for row in db.sql_rows(query) do
+ print(row) -- prints 'Hello, world!'
+ end
]]
function db.sql_rows(stmnt)
@@ -141,14 +150,24 @@ function db.sql_rows(stmnt)
end
end
---[[
-@name lua/db/sqlbind
+--[[ md
+@name lua/db
-Binds an argument to as statement with nice error reporting on failure. Approximatly the same as {{lsqlite/stmt/bind_names}}, but with better error reporting.
-stmnt :: sql.stmnt - the prepared sql statemnet
-call :: string - a string "bind" or "bind_blob"
-position :: number - the argument position to bind to
-data :: string - The data to bind
+### db.sqlbind
+
+Binds an argument to a prepared statement,
+with nice error reporting on failure.
+Wraps {{lsqlite/stmnt/bind_name}}
+with better error reporting.
+
+Parameters:
+
+0. stmnt - {{lsqlite/stmnt}} - The prepared statement from {{sqlite/db/prepare}}
+0. call - {{lua/string}} - Literal string, options are `bind` for most types, or `bind_blob` for strings that may contain embedded nulls
+0. position - {{lua/number}} - The argument position to bind to, does not support named parameters
+0. data - Any - the data to bind
+
+Returns nothing
]]
function db.sqlbind(stmnt,call,position,data)
assert(call == "bind" or call == "bind_blob","Bad bind call, call was:" .. call)
@@ -166,8 +185,6 @@ function db.sqlbind(stmnt,call,position,data)
end
end
-
-
local oldconfigure = configure
db.conn = db.sqlassert(sql.open(config.db))
function configure(...)
@@ -191,6 +208,18 @@ function configure(...)
return oldconfigure(...)
end
+--[[ md
+
+### db.close()
+
+Closes the database connection. Not called during normal operation, used to
+assist in unit testing.
+
+No parameters
+
+No returns
+]]
+
function db.close()
db.conn:close()
end