diff --git a/README.md b/README.md index c23d2cb..23f7423 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,9 @@ Any feedback and suggestions are welcome! This extension is a wrapper for [https://github.com/mmomtchev/sqlite-wasm-http]. Please have a look for more information of the underlying database access implementation. -The http backend is kept open for the lifetime of the element having the corresponding `hx-db` attribute. +The http backend for a query is shared witin the closest element having either `hx-db` or `hx-request` attribute. + +Note that the default `shared` backend type caches SQLite pages in memory. I'm not sure if there's any invalidation. If you have problems seeing changes in the database, try forcing the sync backend. Following events are emitted: - `htmx:xhr:loadstart` when a query execution begins @@ -131,5 +133,5 @@ Use one of attributes #### Override default config ```html -
+ ``` diff --git a/dist/sqlite.js b/dist/sqlite.js index f9225a4..d83473a 100644 --- a/dist/sqlite.js +++ b/dist/sqlite.js @@ -16,6 +16,7 @@ Extension to use SQLite database backend for Htmx over: maxPageSize: 4096, // this is the current default SQLite page size timeout: 10000, // 10s cacheSize: 4096 // 4 MB + //backendType: 'sync' // 'sync' or 'shared'. Defaults to 'shared' if available, otherwise sync; }; sqlConfig = { rowMode: 'object' @@ -84,19 +85,21 @@ Extension to use SQLite database backend for Htmx over: ...sqlConfig, ...conf }; + + var contextElem = htmx.closest(elt, '[hx-db],[hx-request]'); var backend; - if (dbElem._htmx_sqlite_http_backend) { - backend = dbElem._htmx_sqlite_http_backend; + if (contextElem._htmx_sqlite_http_backend) { + backend = contextElem._htmx_sqlite_http_backend; } else { backend = dbURI.match(/^https?:/) ? { http: sqliteWasmHttp.createHttpBackend(config) } : {}; - dbElem._htmx_sqlite_http_backend = backend; + contextElem._htmx_sqlite_http_backend = backend; } - dbElem.addEventListener('htmx:beforeCleanupElement', function(ev) { - if (ev.detail.elt == dbElem && dbElem._htmx_sqlite_http_backend && dbElem._htmx_sqlite_http_backend.http) { - dbElem._htmx_sqlite_http_backend.http.close(); - delete dbElem._htmx_sqlite_http_backend; + contextElem.addEventListener('htmx:beforeCleanupElement', function(ev) { + if (ev.detail.elt == contextElem && contextElem._htmx_sqlite_http_backend && contextElem._htmx_sqlite_http_backend.http) { + contextElem._htmx_sqlite_http_backend.http.close(); + delete contextElem._htmx_sqlite_http_backend; } }); diff --git a/dist/sqlite.min.js b/dist/sqlite.min.js index f26f515..1aea16a 100644 --- a/dist/sqlite.min.js +++ b/dist/sqlite.min.js @@ -1 +1 @@ -(function(){var f;var v;var b;htmx.defineExtension("sqlite",{init:function(e){f=e;v={maxPageSize:4096,timeout:1e4,cacheSize:4096};b={rowMode:"object"}},onEvent:function(e,a){if(e==="htmx:beforeRequest"){let r=a.detail.elt;var t=a.detail.requestConfig;var s;if(t.path==="this.value"||t.verb.toUpperCase()==="GET"&&t.path.toUpperCase().startsWith("SELECT ")||t.verb.toUpperCase()==="PUT"&&t.path.toUpperCase().startsWith("UPDATE ")||t.verb.toUpperCase()==="DELETE"&&t.path.toUpperCase().startsWith("DELETE ")||t.verb.toUpperCase()==="POST"&&t.path.toUpperCase().startsWith("INSERT ")||t.verb.toUpperCase()==="POST"&&t.path.toUpperCase().startsWith("ALTER ")||t.verb.toUpperCase()==="POST"&&t.path.toUpperCase().startsWith("CREATE ")||t.verb.toUpperCase()==="POST"&&t.path.toUpperCase().startsWith("DROP ")||t.verb.toUpperCase()==="POST"&&t.path.toUpperCase().startsWith("TRUNCATE ")){s=t.path}else{return true}if(s==="this.value"){s=r.value;if(!a.detail.target){throw new Error("Attribute 'hx-target' is required when value is used is empty")}}var i=htmx.closest(r,"[hx-db]");if(!i){throw new Error("Attribute 'hx-db' is required in the ancestor hierarchy")}var n=i.getAttribute("hx-db");var h=a.detail.xhr.onload;var p=a.detail.xhr.onerror;a.detail.xhr={status:200,getAllResponseHeaders:function(){return"Content-Type:application/json"},getResponseHeader:function(e){if(e.toLowerCase()==="content-type"){return"application/json"}return undefined}};var o={};Object.entries(a.detail.requestConfig.parameters).forEach(function([e,t]){o["$"+e]=t});var l=htmx.closest(r,"[hx-request]");var c=l?JSON.parse(l.getAttribute("hx-request")):{};var d={...v,...b,...c};var u;if(i._htmx_sqlite_http_backend){u=i._htmx_sqlite_http_backend}else{u=n.match(/^https?:/)?{http:sqliteWasmHttp.createHttpBackend(d)}:{};i._htmx_sqlite_http_backend=u}i.addEventListener("htmx:beforeCleanupElement",function(e){if(e.detail.elt==i&&i._htmx_sqlite_http_backend&&i._htmx_sqlite_http_backend.http){i._htmx_sqlite_http_backend.http.close();delete i._htmx_sqlite_http_backend}});var x=[];sqliteWasmHttp.createSQLiteThread(u).then(function(e){e("open",{filename:encodeURI(n.match(/^https?:\/\//)?n:n.replace(/^opfs:/,"").replace(/^https?:/,"file:")),vfs:n.replace(/:.*/,"").replace("https","http")});return e}).then(function(t){f.triggerEvent(r,"htmx:xhr:loadstart",{elt:r,xhr:{...a.detail.xhr,db:t}});t("exec",{sql:s,bind:o,rowMode:d.rowMode,callback:function(e){if(e.row){x.push(e.row);f.triggerEvent(r,"htmx:xhr:progress",{elt:r,xhr:{...a.detail.xhr,db:t,response:JSON.stringify(e.row),responseJSON:e.row}})}else{f.triggerEvent(r,"htmx:xhr:loadend",{elt:r,xhr:{...a.detail.xhr,db:t,response:x.length==0?"":JSON.stringify(x),responseJSON:x}});t("close",{}).then(function(){t.close()});a.detail.xhr.responseJSON=x;a.detail.xhr.response=JSON.stringify(x);h()}}}).catch(function(e){if(e.result){a.detail.error=e.result.message}p()})});return false}}})})(); \ No newline at end of file +(function(){var v;var b;var _;htmx.defineExtension("sqlite",{init:function(e){v=e;b={maxPageSize:4096,timeout:1e4,cacheSize:4096};_={rowMode:"object"}},onEvent:function(e,a){if(e==="htmx:beforeRequest"){let r=a.detail.elt;var t=a.detail.requestConfig;var s;if(t.path==="this.value"||t.verb.toUpperCase()==="GET"&&t.path.toUpperCase().startsWith("SELECT ")||t.verb.toUpperCase()==="PUT"&&t.path.toUpperCase().startsWith("UPDATE ")||t.verb.toUpperCase()==="DELETE"&&t.path.toUpperCase().startsWith("DELETE ")||t.verb.toUpperCase()==="POST"&&t.path.toUpperCase().startsWith("INSERT ")||t.verb.toUpperCase()==="POST"&&t.path.toUpperCase().startsWith("ALTER ")||t.verb.toUpperCase()==="POST"&&t.path.toUpperCase().startsWith("CREATE ")||t.verb.toUpperCase()==="POST"&&t.path.toUpperCase().startsWith("DROP ")||t.verb.toUpperCase()==="POST"&&t.path.toUpperCase().startsWith("TRUNCATE ")){s=t.path}else{return true}if(s==="this.value"){s=r.value;if(!a.detail.target){throw new Error("Attribute 'hx-target' is required when value is used is empty")}}var i=htmx.closest(r,"[hx-db]");if(!i){throw new Error("Attribute 'hx-db' is required in the ancestor hierarchy")}var n=i.getAttribute("hx-db");var h=a.detail.xhr.onload;var p=a.detail.xhr.onerror;a.detail.xhr={status:200,getAllResponseHeaders:function(){return"Content-Type:application/json"},getResponseHeader:function(e){if(e.toLowerCase()==="content-type"){return"application/json"}return undefined}};var o={};Object.entries(a.detail.requestConfig.parameters).forEach(function([e,t]){o["$"+e]=t});var l=htmx.closest(r,"[hx-request]");var c=l?JSON.parse(l.getAttribute("hx-request")):{};var d={...b,..._,...c};var u=htmx.closest(r,"[hx-db],[hx-request]");var x;if(u._htmx_sqlite_http_backend){x=u._htmx_sqlite_http_backend}else{x=n.match(/^https?:/)?{http:sqliteWasmHttp.createHttpBackend(d)}:{};u._htmx_sqlite_http_backend=x}u.addEventListener("htmx:beforeCleanupElement",function(e){if(e.detail.elt==u&&u._htmx_sqlite_http_backend&&u._htmx_sqlite_http_backend.http){u._htmx_sqlite_http_backend.http.close();delete u._htmx_sqlite_http_backend}});var f=[];sqliteWasmHttp.createSQLiteThread(x).then(function(e){e("open",{filename:encodeURI(n.match(/^https?:\/\//)?n:n.replace(/^opfs:/,"").replace(/^https?:/,"file:")),vfs:n.replace(/:.*/,"").replace("https","http")});return e}).then(function(t){v.triggerEvent(r,"htmx:xhr:loadstart",{elt:r,xhr:{...a.detail.xhr,db:t}});t("exec",{sql:s,bind:o,rowMode:d.rowMode,callback:function(e){if(e.row){f.push(e.row);v.triggerEvent(r,"htmx:xhr:progress",{elt:r,xhr:{...a.detail.xhr,db:t,response:JSON.stringify(e.row),responseJSON:e.row}})}else{v.triggerEvent(r,"htmx:xhr:loadend",{elt:r,xhr:{...a.detail.xhr,db:t,response:f.length==0?"":JSON.stringify(f),responseJSON:f}});t("close",{}).then(function(){t.close()});a.detail.xhr.responseJSON=f;a.detail.xhr.response=JSON.stringify(f);h()}}}).catch(function(e){if(e.result){a.detail.error=e.result.message}p()})});return false}}})})(); \ No newline at end of file diff --git a/package.json b/package.json index b9a6314..b07cbd8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "htmx-sqlite", - "version": "1.9.1", + "version": "1.9.2", "description": "Htmx extension to use SQLite database backend over HTTP or OPFS", "author": "Jyri-Matti Lähteenmäki