{"id":30648128,"url":"https://github.com/liatemplates/sqlite","last_synced_at":"2026-04-14T03:32:38.154Z","repository":{"id":311884027,"uuid":"1045445912","full_name":"LiaTemplates/SQLite","owner":"LiaTemplates","description":"This template enables you to use SQLite databases directly in LiaScript via sql.js. You can create, query, import, and export databases interactively in your Markdown documents.","archived":false,"fork":false,"pushed_at":"2025-08-27T07:29:24.000Z","size":867,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-27T16:22:14.673Z","etag":null,"topics":["database","liascript","liascript-template","markdown","oer","sql","sqlite","sqlite3"],"latest_commit_sha":null,"homepage":"https://liascript.github.io/course/?https://raw.githubusercontent.com/liaTemplates/SQLite/main/README.md","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LiaTemplates.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-27T07:22:22.000Z","updated_at":"2025-08-27T07:42:25.000Z","dependencies_parsed_at":"2025-08-27T16:25:56.769Z","dependency_job_id":"7d1e3d74-4706-4f6f-84f4-0538ced1121b","html_url":"https://github.com/LiaTemplates/SQLite","commit_stats":null,"previous_names":["liatemplates/sqlite"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/LiaTemplates/SQLite","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiaTemplates%2FSQLite","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiaTemplates%2FSQLite/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiaTemplates%2FSQLite/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiaTemplates%2FSQLite/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LiaTemplates","download_url":"https://codeload.github.com/LiaTemplates/SQLite/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiaTemplates%2FSQLite/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31781292,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-14T02:24:21.117Z","status":"ssl_error","status_checked_at":"2026-04-14T02:24:20.627Z","response_time":153,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","liascript","liascript-template","markdown","oer","sql","sqlite","sqlite3"],"created_at":"2025-08-31T05:42:44.894Z","updated_at":"2026-04-14T03:32:38.149Z","avatar_url":"https://github.com/LiaTemplates.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\n\nauthor: André Dietrich\nemail:  LiaScript@web.de\n\ncomment: This script provides functions to interact with SQLite databases in the browser.\n\nlogo:    https://upload.wikimedia.org/wikipedia/commons/thumb/3/38/SQLite370.svg/640px-SQLite370.svg.png\n\nscript: dist/index.js\n\n@onload\nwindow.dbs = window.dbs || {};\n\nwindow.fetchDB = async function(url, name, send) {\n  try {\n    const result = await fetch(url)\n    const data  = await result.arrayBuffer();\n    window.dbs[name] = new SQL.Database(new Uint8Array(data));\n\n    if (send) {\n      send.lia(`loaded database ${name} from ${url}`)\n    }\n  } catch (error) {\n    if (send) {\n      send.lia(`Error fetching database ${name} from ${url}: ${error}`);\n    }\n  }\n}\n\nwindow.exportDB = async function(db, name) {\n  const data = db.export();\n  window.console.log(\"Database exported, size =\", data.length, \"bytes\");\n  const blob = new Blob([data], { type: 'application/x-sqlite3' });\n  const url = URL.createObjectURL(blob);\n  const a = document.createElement('a');\n  a.href = url;\n  a.download = `${name || 'database'}.sqlite`;\n  document.body.appendChild(a);\n  a.click();\n  setTimeout(() =\u003e {\n    document.body.removeChild(a);\n    URL.revokeObjectURL(url);\n  }, 100);\n  return url;\n}\n\nwindow.importDB = function(name) {\n  return new Promise((resolve, reject) =\u003e {\n    const input = document.createElement('input');\n    input.type = 'file';\n    input.accept = '.sqlite,.db,application/x-sqlite3';\n    input.style.display = 'none';\n    document.body.appendChild(input);\n    input.addEventListener('change', async (event) =\u003e {\n      const file = input.files \u0026\u0026 input.files[0];\n      document.body.removeChild(input);\n      if (!file) {\n        reject(\"No file selected\");\n        return;\n      }\n      try {\n        const arrayBuffer = await file.arrayBuffer();\n        const uInt8Array = new Uint8Array(arrayBuffer);\n        const db = new SQL.Database(uInt8Array);\n        db.name = name;\n        window.dbs[name] = db;\n        resolve(\"ok\");\n      } catch (err) {\n        reject(\"Error importing database: \" + err.message);\n      }\n    });\n    input.click();\n  });\n}\n\nwindow.normalizeData = function(data) {\n  // data is an array of { columns, values }\n  return data.flatMap(({ columns, values }) =\u003e\n    values.map((row) =\u003e\n      Object.fromEntries(row.map((cell, i) =\u003e [columns[i], cell]))\n    )\n  );\n}\n\nwindow.toTable = function(data) {\n  const normalized = window.normalizeData(data);\n  return window.consoleTableHTML(normalized);\n}\n\nwindow.runSQL = async function(db, sql, params = []) {\n  const firstWord = (sql.match(/^\\s*([a-z]+)/i)?.[1] || \"\").toUpperCase();\n  const isSelect = firstWord === \"SELECT\" || firstWord === \"WITH\";\n  const isChange = /^(INSERT|UPDATE|DELETE|REPLACE)$/i.test(firstWord);\n  const isCustom = /^(EXPORT|IMPORT)$/i.test(firstWord);\n\n  if (isSelect) {\n    const queryResults = db.exec(sql, params);\n    const rows = window.normalizeData(queryResults);\n    return {\n      type: \"select\",\n      command: firstWord,\n      rows,\n      rowCount: rows.length\n    };\n  } else if (isChange) {\n    db.run(sql, params);\n    const rowsModified = db.getRowsModified();\n    const li = db.exec(\"SELECT last_insert_rowid() AS id\");\n    const lastInsertRowid = li?.[0]?.values?.[0]?.[0] ?? null;\n    return {\n      type: \"change\",\n      command: firstWord,\n      rowsModified,\n      lastInsertRowid\n    };\n  } else if (isCustom) {\n    console.log(\"Custom command detected:\", sql);\n    if (firstWord == \"EXPORT\") {\n      try {\n        const msg = await window.exportDB(db, db.name);\n        console.log(msg);\n      } catch (err) {\n        console.error(err);\n      }\n    } else if (firstWord == \"IMPORT\") {\n      const url = sql.replace(/\\s+/g, ' ').split(\" \")[1]\n\n      if (url) {\n        await window.fetchDB(url, db.name);\n      } else {\n        await window.importDB(db.name);\n      }\n    }\n  } else {\n    // DDL / transaction / pragma etc.\n    db.run(sql, params);\n    return {\n      type: \"command\",\n      command: firstWord || \"UNKNOWN\",\n      success: true\n    };\n  }\n};\n\nwindow.stripSQLComments = function(sql) {\n  return sql\n    // remove /* ... */ block comments\n    .replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\")\n    // remove -- ... end of line comments\n    .replace(/--.*/g, \"\")\n    .trim();\n}\n\n// Render any runSQL() result to HTML\nwindow.formatSQLResultHTML = function(result) {\n  if (!result) return \"\";\n  if (result.type === \"select\") {\n    // Build html table from rows\n    return window.consoleTableHTML(result.rows);\n  }\n  // change/command → status line\n  if (result.type === \"change\") {\n    const n = result.rowsModified ?? 0;\n    const msg = `Query OK, ${n} row${n === 1 ? \"\" : \"s\"} affected` +\n      (result.lastInsertRowid != null ? ` (last id = ${result.lastInsertRowid})` : \"\");\n    return msg;\n  }\n  if (result.type === \"command\") {\n    return result.command + \" OK\";\n  }\n  return \"OK\";\n};\n@end\n\n@SQL.run: \u003cscript\u003e\n    if (!window.dbs[\"@0\"]) {\n        window.dbs[\"@0\"] = new SQL.Database();\n    }\n\n    window.dbs[\"@0\"].name = \"@0\";\n\n    async function run(sql_queries, printCommand=true) {\n        try {\n            sql_queries = window.stripSQLComments(sql_queries || \"\");\n\n            if (sql_queries \u0026\u0026 /\\S/.test(sql_queries)) {\n                sql_queries = sql_queries.split(\";\").map(s =\u003e s.trim()).filter(Boolean);\n\n                for (let i=0; i\u003c sql_queries.length; i++) {\n                    const sql = sql_queries[i];\n\n                    try {\n                        const r = await window.runSQL(window.dbs[\"@0\"], sql);\n                        if (printCommand) console.debug(sql);\n\n                        console.html(window.formatSQLResultHTML(r) || \"\u003cpre\u003eOK\u003c/pre\u003e\");\n                    } catch (err) {\n                        console.error(String(err \u0026\u0026 err.message || err));\n                    }\n\n                    console.log();\n                }\n            }\n        } catch(e) {\n            console.error(\"\\nerror =\u003e\", e);\n        }\n    }\n\n    send.handle(\"input\", (input) =\u003e {\n        run(input, false);\n    });\n\n    run(`@input`);\n\n    \"LIA: terminal\";\n  \u003c/script\u003e\n\n@SQL.run2: \u003cscript\u003e\n    if (!window.dbs[\"@0\"]) {\n        window.dbs[\"@0\"] = new SQL.Database();\n    }\n    window.dbs[\"@0\"].name = \"@0\";\n\n    function run(sql_queries, printCommand=true, hideOutput=false) {\n        try {\n            sql_queries = window.stripSQLComments(sql_queries || \"\");\n\n            if (sql_queries \u0026\u0026 /\\S/.test(sql_queries)) {\n                sql_queries = sql_queries.split(\";\").map(s =\u003e s.trim()).filter(Boolean);\n\n                for (let i=0; i\u003c sql_queries.length; i++) {\n                    const sql = sql_queries[i];\n\n                    try {\n                        const r = window.runSQL(window.dbs[\"@0\"], sql);\n                        if (printCommand \u0026\u0026 !hideOutput) console.debug(sql);\n\n                        if (!hideOutput) {\n                          console.html(window.formatSQLResultHTML(r) || \"\u003cpre\u003eOK\u003c/pre\u003e\");\n                          console.log();\n                        }\n                    } catch (err) {\n                        console.error(String(err \u0026\u0026 err.message || err));\n                    }\n                }\n            }\n        } catch(e) {\n            console.error(\"\\nerror =\u003e\", e);\n        }\n    }\n\n    send.handle(\"input\", (input) =\u003e {\n        run(input, false);\n    });\n\n    run(`@input(0)`, true, true);\n    run(`@input(1)`, true, false);\n\n    \"LIA: terminal\";\n  \u003c/script\u003e\n\nSQL.load: \u003cscript run-once\u003e\n    function loadDB() {\n      if (window.SQL) {\n        window.fetchDB(\"@1\", \"@0\", send);\n      } else {\n        setTimeout(() =\u003e {\n          loadDB();\n        }, 100);\n      }\n    }\n\n    loadDB();\n    \"LIA: wait\"\n  \u003c/script\u003e\n\n--\u003e\n\n# SQL.js - SQLite in the Browser\n\n    --{{0}}--\nThis template enables you to use SQLite databases directly in LiaScript via sql.js. You can create, query, import, and export databases interactively in your Markdown documents.\n\n__Try it on LiaScript:__\n\nhttps://liascript.github.io/course/?https://raw.githubusercontent.com/liaTemplates/SQLite/main/README.md\n\n__See the project on Github:__\n\nhttps://github.com/liaTemplates/SQLite\n\n                         --{{1}}--\nLike with other LiaScript templates, there are three ways to integrate SQL.js:\n\n                           {{1}}\n1. Load the latest macros via (this might cause breaking changes)\n\n   `import: https://raw.githubusercontent.com/liaTemplates/SQLite/main/README.md`\n\n   or the current version 0.0.1 via:\n\n   `import: https://raw.githubusercontent.com/LiaTemplates/SQLite/0.0.1/README.md`\n\n2. Copy the definitions into your Project\n\n3. Clone this repository on GitHub\n\n\n## `@SQL.run`\n\n    --{{0}}--\nExecutes SQL code blocks against the default in-memory database. Each statement is run in sequence, and the results are rendered as HTML tables or status messages. You have to call the macro with a database name, this way different databases can be referenced in the course.\n\n**Example:**\n\n```` markdown\n```SQL\nCREATE TABLE hello (a int, b char);\nINSERT INTO hello VALUES (0, 'hello');\nINSERT INTO hello VALUES (1, 'world');\nSELECT * FROM hello;\n```\n@SQL.run(hello-db)\n\n```SQL\nINSERT INTO hello VALUES (2, 'more');\nINSERT INTO hello VALUES (3, 'updates');\n```\n@SQL.run(hello-db)\n````\n\n------------------\n\n__Result:__\n\n```SQL\nCREATE TABLE hello (a int, b char);\nINSERT INTO hello VALUES (0, 'hello');\nINSERT INTO hello VALUES (1, 'world');\nSELECT * FROM hello;\n```\n@SQL.run(hello-db)\n\n```SQL\nINSERT INTO hello VALUES (2, 'more');\nINSERT INTO hello VALUES (3, 'updates');\n```\n@SQL.run(hello-db)\n\n## `@SQL.run2`\n\n    --{{0}}--\nIf you want to focus on one aspect of the SQL queries and want to hide a part, you can use `@SQL.run2`, which is similar to `@SQL.run`, but it allows to run two code blocks in a row. While you can define with the plus and minus signs, which to show and which to hide.\n\n**Example:**\n\n```` markdown\n```SQL  -populate\n-- Create sales table\nDROP TABLE IF EXISTS sales;\nCREATE TABLE sales (\n  id INTEGER PRIMARY KEY,\n  salesperson TEXT NOT NULL,\n  region TEXT NOT NULL,\n  amount NUMERIC NOT NULL,\n  sale_date DATE NOT NULL\n);\n\n-- Insert sample data\nINSERT INTO sales (salesperson, region, amount, sale_date) VALUES\n  ('Alice', 'North', 12500, '2023-01-05'),\n  ('Bob', 'South', 8700, '2023-01-10'),\n  ('Carol', 'East', 15200, '2023-01-12'),\n  ('Dave', 'West', 7300, '2023-01-15'),\n  ('Alice', 'North', 9800, '2023-02-03'),\n  ('Bob', 'South', 11600, '2023-02-08'),\n  ('Carol', 'East', 14100, '2023-02-15'),\n  ('Dave', 'West', 9200, '2023-02-20'),\n  ('Alice', 'North', 16700, '2023-03-05'),\n  ('Bob', 'South', 10300, '2023-03-12'),\n  ('Carol', 'East', 12800, '2023-03-18'),\n  ('Dave', 'West', 8500, '2023-03-25');\n```\n```SQL  +query\n-- 1. Running total of sales by salesperson\nSELECT\n  salesperson,\n  region,\n  sale_date,\n  amount,\n  SUM(amount) OVER (\n    PARTITION BY salesperson \n    ORDER BY sale_date\n  ) AS running_total\nFROM sales\nORDER BY salesperson, sale_date;\n```\n@SQL.run2(sales)\n````\n\n----\n\n__Result:__\n\n```SQL  -populate\n-- Create sales table\nDROP TABLE IF EXISTS sales;\nCREATE TABLE sales (\n  id INTEGER PRIMARY KEY,\n  salesperson TEXT NOT NULL,\n  region TEXT NOT NULL,\n  amount NUMERIC NOT NULL,\n  sale_date DATE NOT NULL\n);\n\n-- Insert sample data\nINSERT INTO sales (salesperson, region, amount, sale_date) VALUES\n  ('Alice', 'North', 12500, '2023-01-05'),\n  ('Bob', 'South', 8700, '2023-01-10'),\n  ('Carol', 'East', 15200, '2023-01-12'),\n  ('Dave', 'West', 7300, '2023-01-15'),\n  ('Alice', 'North', 9800, '2023-02-03'),\n  ('Bob', 'South', 11600, '2023-02-08'),\n  ('Carol', 'East', 14100, '2023-02-15'),\n  ('Dave', 'West', 9200, '2023-02-20'),\n  ('Alice', 'North', 16700, '2023-03-05'),\n  ('Bob', 'South', 10300, '2023-03-12'),\n  ('Carol', 'East', 12800, '2023-03-18'),\n  ('Dave', 'West', 8500, '2023-03-25');\n```\n```SQL  +query\n-- 1. Running total of sales by salesperson\nSELECT\n  salesperson,\n  region,\n  sale_date,\n  amount,\n  SUM(amount) OVER (\n    PARTITION BY salesperson \n    ORDER BY sale_date\n  ) AS running_total\nFROM sales\nORDER BY salesperson, sale_date;\n```\n@SQL.run2(sales)\n\n## `@SQL.load`\n\n    --{{0}}--\nYou can use this macro to fetch an exported SQLite database file from a given URL and loads it as a database instance. The link macro notation can be used therefor in order to translate relative paths correctly.\n\n**Usage:**\n\n```` markdown\n@[SQL.load(employees)](./sql.db)\n\n```SQL\n-- Query the data\nSELECT \n  department, \n  COUNT(*) as employee_count,\n  ROUND(AVG(salary), 2) as avg_salary\nFROM employees\nGROUP BY department\nORDER BY avg_salary DESC;\n```\n@SQL.run(employees)\n````\n\n@[SQL.load(employees)](./employees.db)\n\n```SQL\n-- Query the data\nSELECT \n  department, \n  COUNT(*) as employee_count,\n  ROUND(AVG(salary), 2) as avg_salary\nFROM employees\nGROUP BY department\nORDER BY avg_salary DESC;\n```\n@SQL.run(employees)\n\n## Custom Commands\n\n### `EXPORT`\n\n    --{{0}}--\nIn order to export the current database to a file, you can use the following command:\n\n```` markdown\n``` SQL\n-- Create a simple employees table\nDROP TABLE IF EXISTS employees;\nCREATE TABLE employees (\n  id INTEGER PRIMARY KEY,\n  name TEXT NOT NULL,\n  department TEXT,\n  salary NUMERIC,\n  hire_date DATE\n);\n\n-- Insert sample data\nINSERT INTO employees (name, department, salary, hire_date) VALUES\n  ('Alice Smith', 'Engineering', 85000, '2020-01-15'),\n  ('Bob Johnson', 'Marketing', 72000, '2019-03-20'),\n  ('Carol Williams', 'Engineering', 92000, '2018-11-07'),\n  ('Dave Brown', 'Finance', 115000, '2017-05-12'),\n  ('Eve Davis', 'Engineering', 110000, '2021-08-30');\n\nEXPORT;\n```\n@SQL.run(employees2)\n````\n\n----------\n\n``` SQL\n-- Create a simple employees table\nDROP TABLE IF EXISTS employees;\nCREATE TABLE employees (\n  id INTEGER PRIMARY KEY,\n  name TEXT NOT NULL,\n  department TEXT,\n  salary NUMERIC,\n  hire_date DATE\n);\n\n-- Insert sample data\nINSERT INTO employees (name, department, salary, hire_date) VALUES\n  ('Alice Smith', 'Engineering', 85000, '2020-01-15'),\n  ('Bob Johnson', 'Marketing', 72000, '2019-03-20'),\n  ('Carol Williams', 'Engineering', 92000, '2018-11-07'),\n  ('Dave Brown', 'Finance', 115000, '2017-05-12'),\n  ('Eve Davis', 'Engineering', 110000, '2021-08-30');\n\nEXPORT;\n```\n@SQL.run(employees2)\n\n\n### `IMPORT`\n\n    --{{0}}--\nIn order to import a previously exported database file, you can use the following command. This will open a file picker dialog to select the database file.\n\n__Example:__\n\n```` markdown\n``` SQL\nIMPORT;\n\nSELECT name, sql\nFROM sqlite_master\nWHERE type='table';\n```\n@SQL.run(import)\n````\n\n-----------------\n\n__Result:__\n\n``` SQL\nIMPORT;\n\nSELECT name, sql\nFROM sqlite_master\nWHERE type='table';\n```\n@SQL.run(import)\n\n      {{1}}\n\u003csection\u003e\n\n    --{{1}}--\nAdditionally you can import an existing database from a http(s) URL:\n\n```` markdown\n``` SQL\nIMPORT https://example.com/path/to/your/database.db;\n\nSELECT name, sql\nFROM sqlite_master\nWHERE type='table';\n```\n@SQL.run(import)\n````\n\n\u003c/section\u003e\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliatemplates%2Fsqlite","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fliatemplates%2Fsqlite","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliatemplates%2Fsqlite/lists"}