jl-db-comp 0.1.9__tar.gz → 0.1.10__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/.gitignore +1 -0
  2. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/CHANGELOG.md +27 -2
  3. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/PKG-INFO +1 -1
  4. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/jl_db_comp/_version.py +1 -1
  5. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/jl_db_comp/labextension/package.json +2 -2
  6. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/jl_db_comp/labextension/schemas/jl_db_comp/package.json.orig +1 -1
  7. jl_db_comp-0.1.9/jl_db_comp/labextension/static/171.d366980651e0db8d978c.js → jl_db_comp-0.1.10/jl_db_comp/labextension/static/171.545011db1d7843ce3ab3.js +1 -1
  8. jl_db_comp-0.1.10/jl_db_comp/labextension/static/remoteEntry.e1b6bbc28eb414e4e599.js +1 -0
  9. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/package.json +1 -1
  10. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/src/provider.ts +54 -20
  11. jl_db_comp-0.1.10/test_nb.ipynb +155 -0
  12. jl_db_comp-0.1.9/jl_db_comp/labextension/static/remoteEntry.0415590cc33a10bfa617.js +0 -1
  13. jl_db_comp-0.1.9/test_nb.ipynb +0 -241
  14. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/.copier-answers.yml +0 -0
  15. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/.prettierignore +0 -0
  16. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/.yarnrc.yml +0 -0
  17. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/AGENTS.md +0 -0
  18. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/CLAUDE.md +0 -0
  19. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/GEMINI.md +0 -0
  20. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/IMPLEMENTATION.md +0 -0
  21. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/LICENSE +0 -0
  22. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/QUICKSTART.md +0 -0
  23. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/README.md +0 -0
  24. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/RELEASE.md +0 -0
  25. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/TESTING.md +0 -0
  26. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/babel.config.js +0 -0
  27. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/conftest.py +0 -0
  28. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/connections.ini +0 -0
  29. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/install.json +0 -0
  30. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/jest.config.js +0 -0
  31. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/jl_db_comp/__init__.py +0 -0
  32. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/jl_db_comp/connections.py +0 -0
  33. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/jl_db_comp/labextension/schemas/jl_db_comp/plugin.json +0 -0
  34. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/jl_db_comp/labextension/static/728.6552504d5b9b27551bc5.js +0 -0
  35. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/jl_db_comp/labextension/static/style.js +0 -0
  36. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/jl_db_comp/labextension/static/third-party-licenses.json +0 -0
  37. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/jl_db_comp/routes.py +0 -0
  38. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/jl_db_comp/tests/__init__.py +0 -0
  39. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/jl_db_comp/tests/test_routes.py +0 -0
  40. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/jupyter-config/server-config/jl_db_comp.json +0 -0
  41. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/pyproject.toml +0 -0
  42. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/schema/plugin.json +0 -0
  43. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/setup.py +0 -0
  44. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/src/__tests__/jl_db_comp.spec.ts +0 -0
  45. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/src/api.ts +0 -0
  46. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/src/index.ts +0 -0
  47. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/src/request.ts +0 -0
  48. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/style/base.css +0 -0
  49. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/style/index.css +0 -0
  50. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/style/index.js +0 -0
  51. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/tsconfig.json +0 -0
  52. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/tsconfig.test.json +0 -0
  53. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/ui-tests/README.md +0 -0
  54. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/ui-tests/jupyter_server_test_config.py +0 -0
  55. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/ui-tests/package.json +0 -0
  56. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/ui-tests/playwright.config.js +0 -0
  57. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/ui-tests/tests/jl_db_comp.spec.ts +0 -0
  58. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/ui-tests/yarn.lock +0 -0
  59. {jl_db_comp-0.1.9 → jl_db_comp-0.1.10}/yarn.lock +0 -0
@@ -68,6 +68,7 @@ htmlcov/
68
68
  .coverage.*
69
69
  .cache
70
70
  nosetests.xml
71
+ junit.xml
71
72
  coverage/
72
73
  coverage.xml
73
74
  *.cover
@@ -2,6 +2,33 @@
2
2
 
3
3
  <!-- <START NEW CHANGELOG ENTRY> -->
4
4
 
5
+ ## 0.1.10
6
+
7
+ ([Full Changelog](https://github.com/Ben-Herz/jl_db_completer/compare/207a722e9c86de77d7c6cc64ca9ffdeacfbe717c...71445c1bc4882acdf6478a77d2a0e2fce0d8af02))
8
+
9
+ ### Enhancements made
10
+
11
+ - get connectin to db from jupysql connections.ini file instead of env [#2](https://github.com/Ben-Herz/jl_db_completer/pull/2) ([@Ben-Herz](https://github.com/Ben-Herz))
12
+
13
+ ### Bugs fixed
14
+
15
+ - jsonb completen should now work on other schemas then public [#4](https://github.com/Ben-Herz/jl_db_completer/pull/4) ([@Ben-Herz](https://github.com/Ben-Herz))
16
+
17
+ ### Other merged PRs
18
+
19
+ - Add JSONB diagnostics logging and troubleshooting endpoint [#1](https://github.com/Ben-Herz/jl_db_completer/pull/1) ([@Ben-Herz](https://github.com/Ben-Herz), [@claude](https://github.com/claude))
20
+
21
+ ### Contributors to this release
22
+
23
+ The following people contributed discussions, new ideas, code and documentation contributions, and review.
24
+ See [our definition of contributors](https://github-activity.readthedocs.io/en/latest/use/#how-does-this-tool-define-contributions-in-the-reports).
25
+
26
+ ([GitHub contributors page for this release](https://github.com/Ben-Herz/jl_db_completer/graphs/contributors?from=2026-01-04&to=2026-01-28&type=c))
27
+
28
+ @Ben-Herz ([activity](https://github.com/search?q=repo%3ABen-Herz%2Fjl_db_completer+involves%3ABen-Herz+updated%3A2026-01-04..2026-01-28&type=Issues)) | @claude ([activity](https://github.com/search?q=repo%3ABen-Herz%2Fjl_db_completer+involves%3Aclaude+updated%3A2026-01-04..2026-01-28&type=Issues))
29
+
30
+ <!-- <END NEW CHANGELOG ENTRY> -->
31
+
5
32
  ## 0.1.9
6
33
 
7
34
  ([Full Changelog](https://github.com/Ben-Herz/jl_db_completer/compare/207a722e9c86de77d7c6cc64ca9ffdeacfbe717c...e66c6da581d00d9d3a90ca8a494e56a1af5e8536))
@@ -23,8 +50,6 @@ See [our definition of contributors](https://github-activity.readthedocs.io/en/l
23
50
 
24
51
  @Ben-Herz ([activity](https://github.com/search?q=repo%3ABen-Herz%2Fjl_db_completer+involves%3ABen-Herz+updated%3A2026-01-02..2026-01-17&type=Issues)) | @claude ([activity](https://github.com/search?q=repo%3ABen-Herz%2Fjl_db_completer+involves%3Aclaude+updated%3A2026-01-02..2026-01-17&type=Issues))
25
52
 
26
- <!-- <END NEW CHANGELOG ENTRY> -->
27
-
28
53
  ## 0.1.8
29
54
 
30
55
  ([Full Changelog](https://github.com/Ben-Herz/jl_db_completer/compare/207a722e9c86de77d7c6cc64ca9ffdeacfbe717c...e66c6da581d00d9d3a90ca8a494e56a1af5e8536))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jl_db_comp
3
- Version: 0.1.9
3
+ Version: 0.1.10
4
4
  Summary: A JupyterLab extension to complete db queries in jupyterlab notebooks
5
5
  Project-URL: Homepage, https://github.com/Ben-Herz/jl_db_completer
6
6
  Project-URL: Bug Tracker, https://github.com/Ben-Herz/jl_db_completer/issues
@@ -1,4 +1,4 @@
1
1
  # This file is auto-generated by Hatchling. As such, do not:
2
2
  # - modify
3
3
  # - track in version control e.g. be sure to add to .gitignore
4
- __version__ = VERSION = '0.1.9'
4
+ __version__ = VERSION = '0.1.10'
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jl_db_comp",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "A JupyterLab extension to complete db queries in jupyterlab notebooks",
5
5
  "keywords": [
6
6
  "jupyter",
@@ -118,7 +118,7 @@
118
118
  "outputDir": "jl_db_comp/labextension",
119
119
  "schemaDir": "schema",
120
120
  "_build": {
121
- "load": "static/remoteEntry.0415590cc33a10bfa617.js",
121
+ "load": "static/remoteEntry.e1b6bbc28eb414e4e599.js",
122
122
  "extension": "./extension",
123
123
  "style": "./style"
124
124
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jl_db_comp",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "A JupyterLab extension to complete db queries in jupyterlab notebooks",
5
5
  "keywords": [
6
6
  "jupyter",
@@ -1 +1 @@
1
- "use strict";(self.webpackChunkjl_db_comp=self.webpackChunkjl_db_comp||[]).push([[171],{171(e,n,t){t.r(n),t.d(n,{default:()=>m});var o=t(206),s=t(428),i=t(490),a=t(830),r=t(469);async function c(e="",n={}){const t=a.ServerConnection.makeSettings(),o=r.URLExt.join(t.baseUrl,"jl-db-comp",e);let s;try{s=await a.ServerConnection.makeRequest(o,n,t)}catch(e){throw new a.ServerConnection.NetworkError(e)}let i=await s.text();if(i.length>0)try{i=JSON.parse(i)}catch(e){console.log("Not a JSON response body.",s)}if(!s.ok)throw new a.ServerConnection.ResponseError(s,i.message||i);return i}class l{constructor(e,n){this.identifier="jl_db_comp:postgres-completer",this.renderer=null,this._cache=new Map,this._cacheTTL=3e5,this._settings=null,this._notebookTracker=null,this._connectionName="",this._schema="public",this._enabled=!0,this._availableConnections=[],this._cachedKernelConfig=null,this._kernelConfigCacheTime=0,this._kernelConfigCacheTTL=3e4,this._sqlKeywords=["select","from","join","where","insert","update","delete","inner","left","right","outer","on","group","order","by","having","into","values","set"],this._notebookTracker=n||null,e&&(this._settings=e,this._loadSettings(),e.changed.connect(()=>{this._loadSettings()})),this._loadAvailableConnections()}_loadSettings(){this._settings&&(this._connectionName=this._settings.get("connectionName").composite,this._schema=this._settings.get("schema").composite,this._enabled=this._settings.get("enabled").composite)}async _loadAvailableConnections(){try{const e=await async function(){try{return await c("connections",{method:"GET"})}catch(e){if(e instanceof a.ServerConnection.ResponseError)console.error(`Failed to fetch connections: ${e.message}`);else{const n=e instanceof Error?e.message:"Unknown error";console.error(`Failed to fetch connections: ${n}`)}return{status:"error",connections:{},filePath:null,message:"Failed to fetch connections"}}}();"success"===e.status&&(this._availableConnections=Object.keys(e.connections))}catch(e){console.warn("Failed to load available connections:",e)}}async _getKernelConfig(){var e;const n=Date.now();if(this._cachedKernelConfig&&n-this._kernelConfigCacheTime<this._kernelConfigCacheTTL)return this._cachedKernelConfig;if(!this._notebookTracker)return null;const t=this._notebookTracker.currentWidget;if(!t)return null;const o=null===(e=t.sessionContext.session)||void 0===e?void 0:e.kernel;if(!o)return null;try{const e=o.requestExecute({code:"\nimport json\nimport os\nresult = {'connection': '', 'dsn_filename': ''}\n\n# Get active connection\ntry:\n from sql.connection import ConnectionManager\n conn = ConnectionManager.current\n if conn:\n for alias, c in ConnectionManager.connections.items():\n if c is conn:\n result['connection'] = alias\n break\nexcept:\n pass\n\n# Get dsn_filename from SqlMagic instance\ndsn_filename = None\ntry:\n from sql.magic import SqlMagic\n ip = get_ipython()\n if ip:\n for name, inst in ip.magics_manager.registry.items():\n if isinstance(inst, SqlMagic):\n dsn_filename = inst.dsn_filename\n break\nexcept:\n pass\n\n# Fallback: try to get from config\nif not dsn_filename:\n try:\n ip = get_ipython()\n if ip and hasattr(ip, 'config'):\n sql_config = ip.config.get('SqlMagic', {})\n if 'dsn_filename' in sql_config:\n dsn_filename = sql_config['dsn_filename']\n except:\n pass\n\n# Convert to absolute path if we have a dsn_filename\nif dsn_filename:\n if not os.path.isabs(dsn_filename):\n # Resolve relative to current working directory\n dsn_filename = os.path.abspath(dsn_filename)\n result['dsn_filename'] = dsn_filename\n\nprint(json.dumps(result))\n",silent:!0,store_history:!1}),t=await new Promise(n=>{let t="";e.onIOPub=e=>{if("stream"===e.header.msg_type){const n=e.content;"stdout"===n.name&&(t+=n.text)}},e.done.then(()=>{try{const e=JSON.parse(t.trim());n({connection:e.connection||"",dsnFilename:e.dsn_filename||""})}catch(e){n(null)}}).catch(()=>{n(null)})});return t&&(this._cachedKernelConfig=t,this._kernelConfigCacheTime=n),t}catch(e){return console.warn("Failed to get jupysql config from kernel:",e),null}}async isApplicable(e){if(!this._enabled)return!1;const n=e.editor;if(!n)return!1;const t=n.model.sharedModel.getSource();if(!t)return!1;const o=t.toLowerCase();return this._sqlKeywords.some(e=>o.includes(e))}async fetch(e,n){var t;if(!this._enabled)return{start:e.offset,end:e.offset,items:[]};const{text:o,offset:s}=e,i=this._extractContext(o,s);let r;if(i.jsonbColumn){const e=(null===(t=i.jsonbPath)||void 0===t?void 0:t.join("."))||"";r=`${i.schemaOrTable?`${i.schemaOrTable}.`:""}${i.jsonbColumn}->${e}.${i.prefix}`.toLowerCase()}else r=i.schema&&i.tableName?`${i.schema}.${i.tableName}.${i.prefix}`.toLowerCase():i.schemaOrTable?`${i.schemaOrTable}.${i.prefix}`.toLowerCase():i.prefix.toLowerCase();const l=this._getCached(r);if(l)return this._formatReply(l,e.offset,i.prefix);try{const n=await this._getKernelConfig();let t,o=this._connectionName;n&&(n.dsnFilename&&(t=n.dsnFilename),!o&&n.connection&&(o=n.connection)),!o&&this._availableConnections.length>0&&(o=this._availableConnections[0]);const s=await async function(e,n="",t="public",o,s,i,r,l){try{const a=new URLSearchParams;e&&a.append("connection",e),l&&a.append("connections_file",l),n&&a.append("prefix",n),a.append("schema",t),o&&a.append("table",o),s&&a.append("schema_or_table",s),i&&(a.append("jsonb_column",i),r&&r.length>0&&a.append("jsonb_path",JSON.stringify(r)));const h=`completions?${a.toString()}`,m=await c(h,{method:"GET"});return"error"===m.status?(console.error("PostgreSQL completion error:",m.message),[]):i&&m.jsonbKeys?m.jsonbKeys:o||s?m.columns.length>0?m.columns:m.tables:[...m.tables,...m.columns]}catch(e){if(e instanceof a.ServerConnection.ResponseError){const n=e.response.status;let t=e.message;"string"==typeof t&&(t.includes("<!DOCTYPE")||t.includes("<html"))&&(t=`HTML error page (${t.substring(0,100)}...)`),console.error(`PostgreSQL completions API failed (${n}): ${t}`)}else{const n=e instanceof Error?e.message:"Unknown error";console.error(`PostgreSQL completions API failed: ${n}`)}return[]}}(o||void 0,i.prefix,i.schema||this._schema,i.tableName,i.schemaOrTable,i.jsonbColumn,i.jsonbPath,t);return this._cache.set(r,{items:s,timestamp:Date.now()}),this._formatReply(s,e.offset,i.prefix)}catch(n){return console.error("Failed to fetch PostgreSQL completions:",n),{start:e.offset,end:e.offset,items:[]}}}_extractContext(e,n){const t=e.substring(0,n);if(t.includes("->")){const e=t.match(/([\w]+\.)?([\w]+)\s*->\s*(.*)$/);if(e){const n=e[1]?e[1].slice(0,-1):void 0,t=e[2],o=e[3],s=[],i=/['"]?([\w]+)['"]?\s*->/g;let a;for(;null!==(a=i.exec(o));)s.push(a[1]);const r=o.lastIndexOf("->");let c="";return c=r>=0?o.substring(r+2).trim().replace(/['"]/g,""):o.trim().replace(/['"]/g,""),{schemaOrTable:n,jsonbColumn:t,jsonbPath:s,prefix:c}}}const o=t.match(/([\w]+)\.([\w]+)\.([\w]*)$/);if(o)return{schema:o[1],tableName:o[2],prefix:o[3]};const s=t.match(/([\w]+)\.([\w]*)$/);if(s)return{schemaOrTable:s[1],prefix:s[2]};const i=t.match(/[\w]+$/),a=i?i[0]:"",r=e.toLowerCase().match(/\bfrom\s+([\w]+\.)?[\w]+/);if(r){const e=r[0].match(/\bfrom\s+(?:([\w]+)\.)?([\w]+)/);if(e){const n=e[1],t=e[2];return n?{schema:n,tableName:t,prefix:a}:{schemaOrTable:t,prefix:a}}}return{prefix:a}}_getCached(e){const n=e.toLowerCase(),t=this._cache.get(n);return t?Date.now()-t.timestamp>this._cacheTTL?(this._cache.delete(n),null):t.items:null}_formatReply(e,n,t){return{start:n-t.length,end:n,items:e.map(e=>{let n=e.name,t=e.name;"jsonb_key"===e.type&&(t=`'${e.name}'`),"column"===e.type&&e.table&&(n=`${e.name} (${e.table})`);let o,s="📊",i=e.name;return"table"===e.type?s="📋":"view"===e.type?s="👁️":"jsonb_key"===e.type&&(s="🔑",i=`0000${e.name}`),"column"===e.type&&e.dataType&&e.table?o=`${e.table}.${e.name}: ${e.dataType}`:"jsonb_key"===e.type&&e.keyPath&&(o=`JSONB key: ${e.keyPath.join(" -> ")}`),{label:`${s} ${n}`,insertText:t,sortText:i,type:e.type,documentation:o}})}}clearCache(){this._cache.clear()}}const h="jl_db_comp:plugin",m={id:h,description:"A JupyterLab extension to complete db queries in jupyterlab notebooks",autoStart:!0,requires:[o.ICompletionProviderManager],optional:[i.ISettingRegistry,s.INotebookTracker],activate:(e,n,t,o)=>{let s;t?t.load(h).then(e=>{s=new l(e,o),n.registerProvider(s),console.log("JupyterLab extension jl_db_comp is activated!")}).catch(e=>{console.error("Failed to load settings for jl_db_comp:",e),s=new l(null,o),n.registerProvider(s),console.log("JupyterLab extension jl_db_comp is activated!")}):(s=new l(null,o),n.registerProvider(s),console.log("JupyterLab extension jl_db_comp is activated!"))}}}}]);
1
+ "use strict";(self.webpackChunkjl_db_comp=self.webpackChunkjl_db_comp||[]).push([[171],{171(e,n,t){t.r(n),t.d(n,{default:()=>m});var o=t(141),s=t(931),i=t(249),a=t(125),r=t(526);async function c(e="",n={}){const t=a.ServerConnection.makeSettings(),o=r.URLExt.join(t.baseUrl,"jl-db-comp",e);let s;try{s=await a.ServerConnection.makeRequest(o,n,t)}catch(e){throw new a.ServerConnection.NetworkError(e)}let i=await s.text();if(i.length>0)try{i=JSON.parse(i)}catch(e){console.log("Not a JSON response body.",s)}if(!s.ok)throw new a.ServerConnection.ResponseError(s,i.message||i);return i}class l{constructor(e,n){this.identifier="jl_db_comp:postgres-completer",this.renderer=null,this._cache=new Map,this._cacheTTL=3e5,this._settings=null,this._notebookTracker=null,this._connectionName="",this._schema="public",this._enabled=!0,this._availableConnections=[],this._cachedKernelConfig=null,this._kernelConfigCacheTime=0,this._kernelConfigCacheTTL=3e4,this._sqlKeywords=["select","from","join","where","insert","update","delete","inner","left","right","outer","on","group","order","by","having","into","values","set"],this._notebookTracker=n||null,e&&(this._settings=e,this._loadSettings(),e.changed.connect(()=>{this._loadSettings()})),this._loadAvailableConnections()}_loadSettings(){this._settings&&(this._connectionName=this._settings.get("connectionName").composite,this._schema=this._settings.get("schema").composite,this._enabled=this._settings.get("enabled").composite)}async _loadAvailableConnections(){try{const e=await async function(){try{return await c("connections",{method:"GET"})}catch(e){if(e instanceof a.ServerConnection.ResponseError)console.error(`Failed to fetch connections: ${e.message}`);else{const n=e instanceof Error?e.message:"Unknown error";console.error(`Failed to fetch connections: ${n}`)}return{status:"error",connections:{},filePath:null,message:"Failed to fetch connections"}}}();"success"===e.status&&(this._availableConnections=Object.keys(e.connections))}catch(e){console.warn("Failed to load available connections:",e)}}async _getKernelConfig(){var e;const n=Date.now();if(this._cachedKernelConfig&&n-this._kernelConfigCacheTime<this._kernelConfigCacheTTL)return this._cachedKernelConfig;if(!this._notebookTracker)return null;const t=this._notebookTracker.currentWidget;if(!t)return null;const o=null===(e=t.sessionContext.session)||void 0===e?void 0:e.kernel;if(!o)return null;try{const e=o.requestExecute({code:"\nimport json\nimport os\nresult = {'connection': '', 'dsn_filename': ''}\n\n# Get active connection\ntry:\n from sql.connection import ConnectionManager\n conn = ConnectionManager.current\n if conn:\n for alias, c in ConnectionManager.connections.items():\n if c is conn:\n result['connection'] = alias\n break\nexcept:\n pass\n\n# Get dsn_filename from SqlMagic instance\ndsn_filename = None\ntry:\n from sql.magic import SqlMagic\n ip = get_ipython()\n if ip:\n for name, inst in ip.magics_manager.registry.items():\n if isinstance(inst, SqlMagic):\n dsn_filename = inst.dsn_filename\n break\nexcept:\n pass\n\n# Fallback: try to get from config\nif not dsn_filename:\n try:\n ip = get_ipython()\n if ip and hasattr(ip, 'config'):\n sql_config = ip.config.get('SqlMagic', {})\n if 'dsn_filename' in sql_config:\n dsn_filename = sql_config['dsn_filename']\n except:\n pass\n\n# Convert to absolute path if we have a dsn_filename\nif dsn_filename:\n if not os.path.isabs(dsn_filename):\n # Resolve relative to current working directory\n dsn_filename = os.path.abspath(dsn_filename)\n result['dsn_filename'] = dsn_filename\n\nprint(json.dumps(result))\n",silent:!0,store_history:!1}),t=await new Promise(n=>{let t="";e.onIOPub=e=>{if("stream"===e.header.msg_type){const n=e.content;"stdout"===n.name&&(t+=n.text)}},e.done.then(()=>{try{const e=JSON.parse(t.trim());n({connection:e.connection||"",dsnFilename:e.dsn_filename||""})}catch(e){n(null)}}).catch(()=>{n(null)})});return t&&(this._cachedKernelConfig=t,this._kernelConfigCacheTime=n),t}catch(e){return console.warn("Failed to get jupysql config from kernel:",e),null}}async isApplicable(e){if(!this._enabled)return!1;const n=e.editor;if(!n)return!1;const t=n.model.sharedModel.getSource();if(!t)return!1;const o=t.toLowerCase();return this._sqlKeywords.some(e=>o.includes(e))}async fetch(e,n){var t;if(!this._enabled)return{start:e.offset,end:e.offset,items:[]};const{text:o,offset:s}=e,i=this._extractContext(o,s);let r;if(i.jsonbColumn){const e=(null===(t=i.jsonbPath)||void 0===t?void 0:t.join("."))||"";r=`${i.schemaOrTable?`${i.schemaOrTable}.`:""}${i.jsonbColumn}->${e}.${i.prefix}`.toLowerCase()}else r=i.schema&&i.tableName?`${i.schema}.${i.tableName}.${i.prefix}`.toLowerCase():i.schemaOrTable?`${i.schemaOrTable}.${i.prefix}`.toLowerCase():i.prefix.toLowerCase();const l=this._getCached(r);if(l)return this._formatReply(l,e.offset,i.prefix);try{const n=await this._getKernelConfig();let t,o=this._connectionName;n&&(n.dsnFilename&&(t=n.dsnFilename),!o&&n.connection&&(o=n.connection)),!o&&this._availableConnections.length>0&&(o=this._availableConnections[0]);const s=await async function(e,n="",t="public",o,s,i,r,l){try{const a=new URLSearchParams;e&&a.append("connection",e),l&&a.append("connections_file",l),n&&a.append("prefix",n),a.append("schema",t),o&&a.append("table",o),s&&a.append("schema_or_table",s),i&&(a.append("jsonb_column",i),r&&r.length>0&&a.append("jsonb_path",JSON.stringify(r)));const h=`completions?${a.toString()}`,m=await c(h,{method:"GET"});return"error"===m.status?(console.error("PostgreSQL completion error:",m.message),[]):i&&m.jsonbKeys?m.jsonbKeys:o||s?m.columns.length>0?m.columns:m.tables:[...m.tables,...m.columns]}catch(e){if(e instanceof a.ServerConnection.ResponseError){const n=e.response.status;let t=e.message;"string"==typeof t&&(t.includes("<!DOCTYPE")||t.includes("<html"))&&(t=`HTML error page (${t.substring(0,100)}...)`),console.error(`PostgreSQL completions API failed (${n}): ${t}`)}else{const n=e instanceof Error?e.message:"Unknown error";console.error(`PostgreSQL completions API failed: ${n}`)}return[]}}(o||void 0,i.prefix,i.schema||this._schema,i.tableName,i.schemaOrTable,i.jsonbColumn,i.jsonbPath,t);return this._cache.set(r,{items:s,timestamp:Date.now()}),this._formatReply(s,e.offset,i.prefix)}catch(n){return console.error("Failed to fetch PostgreSQL completions:",n),{start:e.offset,end:e.offset,items:[]}}}_extractContext(e,n){const t=e.substring(0,n);if(t.includes("->")){const e=e=>{const n=[],t=/['"]?([\w]+)['"]?\s*->/g;let o;for(;null!==(o=t.exec(e));)n.push(o[1]);const s=e.lastIndexOf("->");let i="";return i=s>=0?e.substring(s+2).trim().replace(/['"]/g,""):e.trim().replace(/['"]/g,""),{jsonbPath:n,prefix:i}},n=t.match(/([\w]+)\.([\w]+)\.([\w]+)\s*->\s*(.*)$/);if(n){const t=n[1],o=n[2],s=n[3],i=n[4],{jsonbPath:a,prefix:r}=e(i);return{schema:t,tableName:o,jsonbColumn:s,jsonbPath:a,prefix:r}}const o=t.match(/([\w]+)\.([\w]+)\s*->\s*(.*)$/);if(o){const n=o[1],t=o[2],s=o[3],{jsonbPath:i,prefix:a}=e(s);return{schemaOrTable:n,jsonbColumn:t,jsonbPath:i,prefix:a}}const s=t.match(/([\w]+)\s*->\s*(.*)$/);if(s){const n=s[1],t=s[2],{jsonbPath:o,prefix:i}=e(t);return{jsonbColumn:n,jsonbPath:o,prefix:i}}}const o=t.match(/([\w]+)\.([\w]+)\.([\w]*)$/);if(o)return{schema:o[1],tableName:o[2],prefix:o[3]};const s=t.match(/([\w]+)\.([\w]*)$/);if(s)return{schemaOrTable:s[1],prefix:s[2]};const i=t.match(/[\w]+$/),a=i?i[0]:"",r=e.toLowerCase().match(/\bfrom\s+([\w]+\.)?[\w]+/);if(r){const e=r[0].match(/\bfrom\s+(?:([\w]+)\.)?([\w]+)/);if(e){const n=e[1],t=e[2];return n?{schema:n,tableName:t,prefix:a}:{schemaOrTable:t,prefix:a}}}return{prefix:a}}_getCached(e){const n=e.toLowerCase(),t=this._cache.get(n);return t?Date.now()-t.timestamp>this._cacheTTL?(this._cache.delete(n),null):t.items:null}_formatReply(e,n,t){return{start:n-t.length,end:n,items:e.map(e=>{let n=e.name,t=e.name;"jsonb_key"===e.type&&(t=`'${e.name}'`),"column"===e.type&&e.table&&(n=`${e.name} (${e.table})`);let o,s="📊",i=e.name;return"table"===e.type?s="📋":"view"===e.type?s="👁️":"jsonb_key"===e.type&&(s="🔑",i=`0000${e.name}`),"column"===e.type&&e.dataType&&e.table?o=`${e.table}.${e.name}: ${e.dataType}`:"jsonb_key"===e.type&&e.keyPath&&(o=`JSONB key: ${e.keyPath.join(" -> ")}`),{label:`${s} ${n}`,insertText:t,sortText:i,type:e.type,documentation:o}})}}clearCache(){this._cache.clear()}}const h="jl_db_comp:plugin",m={id:h,description:"A JupyterLab extension to complete db queries in jupyterlab notebooks",autoStart:!0,requires:[o.ICompletionProviderManager],optional:[i.ISettingRegistry,s.INotebookTracker],activate:(e,n,t,o)=>{let s;t?t.load(h).then(e=>{s=new l(e,o),n.registerProvider(s),console.log("JupyterLab extension jl_db_comp is activated!")}).catch(e=>{console.error("Failed to load settings for jl_db_comp:",e),s=new l(null,o),n.registerProvider(s),console.log("JupyterLab extension jl_db_comp is activated!")}):(s=new l(null,o),n.registerProvider(s),console.log("JupyterLab extension jl_db_comp is activated!"))}}}}]);
@@ -0,0 +1 @@
1
+ var _JUPYTERLAB;(()=>{"use strict";var e,r,t,n,o,a,i,u,l,s,f,c,d,p,h,v,b,g,m,y={246(e,r,t){var n={"./index":()=>t.e(171).then(()=>()=>t(171)),"./extension":()=>t.e(171).then(()=>()=>t(171)),"./style":()=>t.e(728).then(()=>()=>t(728))},o=(e,r)=>(t.R=r,r=t.o(n,e)?n[e]():Promise.resolve().then(()=>{throw new Error('Module "'+e+'" does not exist in container.')}),t.R=void 0,r),a=(e,r)=>{if(t.S){var n="default",o=t.S[n];if(o&&o!==e)throw new Error("Container initialization failed as it has already been initialized with a different share scope");return t.S[n]=e,t.I(n,r)}};t.d(r,{get:()=>o,init:()=>a})}},w={};function j(e){var r=w[e];if(void 0!==r)return r.exports;var t=w[e]={id:e,exports:{}};return y[e](t,t.exports,j),t.exports}j.m=y,j.c=w,j.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return j.d(r,{a:r}),r},j.d=(e,r)=>{for(var t in r)j.o(r,t)&&!j.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},j.f={},j.e=e=>Promise.all(Object.keys(j.f).reduce((r,t)=>(j.f[t](e,r),r),[])),j.u=e=>e+"."+{171:"545011db1d7843ce3ab3",728:"6552504d5b9b27551bc5"}[e]+".js?v="+{171:"545011db1d7843ce3ab3",728:"6552504d5b9b27551bc5"}[e],j.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),j.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},r="jl_db_comp:",j.l=(t,n,o,a)=>{if(e[t])e[t].push(n);else{var i,u;if(void 0!==o)for(var l=document.getElementsByTagName("script"),s=0;s<l.length;s++){var f=l[s];if(f.getAttribute("src")==t||f.getAttribute("data-webpack")==r+o){i=f;break}}i||(u=!0,(i=document.createElement("script")).charset="utf-8",j.nc&&i.setAttribute("nonce",j.nc),i.setAttribute("data-webpack",r+o),i.src=t),e[t]=[n];var c=(r,n)=>{i.onerror=i.onload=null,clearTimeout(d);var o=e[t];if(delete e[t],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach(e=>e(n)),r)return r(n)},d=setTimeout(c.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=c.bind(null,i.onerror),i.onload=c.bind(null,i.onload),u&&document.head.appendChild(i)}},j.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{j.S={};var e={},r={};j.I=(t,n)=>{n||(n=[]);var o=r[t];if(o||(o=r[t]={}),!(n.indexOf(o)>=0)){if(n.push(o),e[t])return e[t];j.o(j.S,t)||(j.S[t]={});var a=j.S[t],i="jl_db_comp",u=[];return"default"===t&&((e,r,t,n)=>{var o=a[e]=a[e]||{},u=o[r];(!u||!u.loaded&&(1!=!u.eager?n:i>u.from))&&(o[r]={get:()=>j.e(171).then(()=>()=>j(171)),from:i,eager:!1})})("jl_db_comp","0.1.10"),e[t]=u.length?Promise.all(u).then(()=>e[t]=1):1}}})(),(()=>{var e;j.g.importScripts&&(e=j.g.location+"");var r=j.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),j.p=e})(),t=e=>{var r=e=>e.split(".").map(e=>+e==e?+e:e),t=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(e),n=t[1]?r(t[1]):[];return t[2]&&(n.length++,n.push.apply(n,r(t[2]))),t[3]&&(n.push([]),n.push.apply(n,r(t[3]))),n},n=(e,r)=>{e=t(e),r=t(r);for(var n=0;;){if(n>=e.length)return n<r.length&&"u"!=(typeof r[n])[0];var o=e[n],a=(typeof o)[0];if(n>=r.length)return"u"==a;var i=r[n],u=(typeof i)[0];if(a!=u)return"o"==a&&"n"==u||"s"==u||"u"==a;if("o"!=a&&"u"!=a&&o!=i)return o<i;n++}},o=e=>{var r=e[0],t="";if(1===e.length)return"*";if(r+.5){t+=0==r?">=":-1==r?"<":1==r?"^":2==r?"~":r>0?"=":"!=";for(var n=1,a=1;a<e.length;a++)n--,t+="u"==(typeof(u=e[a]))[0]?"-":(n>0?".":"")+(n=2,u);return t}var i=[];for(a=1;a<e.length;a++){var u=e[a];i.push(0===u?"not("+l()+")":1===u?"("+l()+" || "+l()+")":2===u?i.pop()+" "+i.pop():o(u))}return l();function l(){return i.pop().replace(/^\((.+)\)$/,"$1")}},a=(e,r)=>{if(0 in e){r=t(r);var n=e[0],o=n<0;o&&(n=-n-1);for(var i=0,u=1,l=!0;;u++,i++){var s,f,c=u<e.length?(typeof e[u])[0]:"";if(i>=r.length||"o"==(f=(typeof(s=r[i]))[0]))return!l||("u"==c?u>n&&!o:""==c!=o);if("u"==f){if(!l||"u"!=c)return!1}else if(l)if(c==f)if(u<=n){if(s!=e[u])return!1}else{if(o?s>e[u]:s<e[u])return!1;s!=e[u]&&(l=!1)}else if("s"!=c&&"n"!=c){if(o||u<=n)return!1;l=!1,u--}else{if(u<=n||f<c!=o)return!1;l=!1}else"s"!=c&&"n"!=c&&(l=!1,u--)}}var d=[],p=d.pop.bind(d);for(i=1;i<e.length;i++){var h=e[i];d.push(1==h?p()|p():2==h?p()&p():h?a(h,r):!p())}return!!p()},i=(e,r)=>e&&j.o(e,r),u=e=>(e.loaded=1,e.get()),l=e=>Object.keys(e).reduce((r,t)=>(e[t].eager&&(r[t]=e[t]),r),{}),s=(e,r,t)=>{var o=t?l(e[r]):e[r];return Object.keys(o).reduce((e,r)=>!e||!o[e].loaded&&n(e,r)?r:e,0)},f=(e,r,t,n)=>"Unsatisfied version "+t+" from "+(t&&e[r][t].from)+" of shared singleton module "+r+" (required "+o(n)+")",c=e=>{throw new Error(e)},d=e=>{"undefined"!=typeof console&&console.warn&&console.warn(e)},p=(e,r,t)=>t?t():((e,r)=>c("Shared module "+r+" doesn't exist in shared scope "+e))(e,r),h=(e=>function(r,t,n,o,a){var i=j.I(r);return i&&i.then&&!n?i.then(e.bind(e,r,j.S[r],t,!1,o,a)):e(r,j.S[r],t,n,o,a)})((e,r,t,n,o,l)=>{if(!i(r,t))return p(e,t,l);var c=s(r,t,n);return a(o,c)||d(f(r,t,c,o)),u(r[t][c])}),v={},b={125:()=>h("default","@jupyterlab/services",!1,[1,7,5,3]),141:()=>h("default","@jupyterlab/completer",!1,[1,4,5,3]),249:()=>h("default","@jupyterlab/settingregistry",!1,[1,4,5,3]),526:()=>h("default","@jupyterlab/coreutils",!1,[1,6,5,3]),931:()=>h("default","@jupyterlab/notebook",!1,[1,4,5,3])},g={171:[125,141,249,526,931]},m={},j.f.consumes=(e,r)=>{j.o(g,e)&&g[e].forEach(e=>{if(j.o(v,e))return r.push(v[e]);if(!m[e]){var t=r=>{v[e]=0,j.m[e]=t=>{delete j.c[e],t.exports=r()}};m[e]=!0;var n=r=>{delete v[e],j.m[e]=t=>{throw delete j.c[e],r}};try{var o=b[e]();o.then?r.push(v[e]=o.then(t).catch(n)):t(o)}catch(e){n(e)}}})},(()=>{var e={248:0};j.f.j=(r,t)=>{var n=j.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var o=new Promise((t,o)=>n=e[r]=[t,o]);t.push(n[2]=o);var a=j.p+j.u(r),i=new Error;j.l(a,t=>{if(j.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var o=t&&("load"===t.type?"missing":t.type),a=t&&t.target&&t.target.src;i.message="Loading chunk "+r+" failed.\n("+o+": "+a+")",i.name="ChunkLoadError",i.type=o,i.request=a,n[1](i)}},"chunk-"+r,r)}};var r=(r,t)=>{var n,o,[a,i,u]=t,l=0;if(a.some(r=>0!==e[r])){for(n in i)j.o(i,n)&&(j.m[n]=i[n]);u&&u(j)}for(r&&r(t);l<a.length;l++)o=a[l],j.o(e,o)&&e[o]&&e[o][0](),e[o]=0},t=self.webpackChunkjl_db_comp=self.webpackChunkjl_db_comp||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),j.nc=void 0;var S=j(246);(_JUPYTERLAB=void 0===_JUPYTERLAB?{}:_JUPYTERLAB).jl_db_comp=S})();
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jl_db_comp",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "A JupyterLab extension to complete db queries in jupyterlab notebooks",
5
5
  "keywords": [
6
6
  "jupyter",
@@ -418,21 +418,12 @@ export class PostgresCompletionProvider implements ICompletionProvider {
418
418
 
419
419
  // JSONB pattern: Detect -> or ->> operators
420
420
  // Examples: metadata-> or content -> or patients.metadata->>'key'->
421
+ // Also handles: schema.table.column-> for non-public schemas
421
422
  if (beforeCursor.includes('->')) {
422
- // Much simpler approach: find the last -> or ->> and work backwards
423
- // Look for: word characters, optional dot+word, then ->, then anything
424
- // Pattern: (word.)?word -> rest
425
- const simpleMatch = beforeCursor.match(/([\w]+\.)?([\w]+)\s*->\s*(.*)$/);
426
-
427
- if (simpleMatch) {
428
- const tableOrSchema = simpleMatch[1]
429
- ? simpleMatch[1].slice(0, -1)
430
- : undefined; // Remove trailing dot
431
- const columnName = simpleMatch[2];
432
- const afterOperator = simpleMatch[3];
433
-
434
- // Parse the path after the first ->
435
- // Example: "'key1'->>'key2'->" or "key1" or ""
423
+ // Helper to parse the path after the first -> operator
424
+ const parseJsonbPath = (
425
+ afterOperator: string
426
+ ): { jsonbPath: string[]; prefix: string } => {
436
427
  const jsonbPath: string[] = [];
437
428
  const pathRegex = /['"]?([\w]+)['"]?\s*->/g;
438
429
  let pathMatch;
@@ -441,24 +432,67 @@ export class PostgresCompletionProvider implements ICompletionProvider {
441
432
  }
442
433
 
443
434
  // Get the current prefix (what's being typed after the last ->)
444
- // Remove any keys that are part of the path
445
435
  const lastArrowIndex = afterOperator.lastIndexOf('->');
446
- let currentPrefix = '';
436
+ let prefix = '';
447
437
  if (lastArrowIndex >= 0) {
448
- currentPrefix = afterOperator
438
+ prefix = afterOperator
449
439
  .substring(lastArrowIndex + 2)
450
440
  .trim()
451
441
  .replace(/['"]/g, '');
452
442
  } else {
453
- // No nested path, just get whatever is after the ->
454
- currentPrefix = afterOperator.trim().replace(/['"]/g, '');
443
+ prefix = afterOperator.trim().replace(/['"]/g, '');
455
444
  }
456
445
 
446
+ return { jsonbPath, prefix };
447
+ };
448
+
449
+ // Three-part JSONB pattern: schema.table.column->
450
+ const threePartMatch = beforeCursor.match(
451
+ /([\w]+)\.([\w]+)\.([\w]+)\s*->\s*(.*)$/
452
+ );
453
+ if (threePartMatch) {
454
+ const schema = threePartMatch[1];
455
+ const tableName = threePartMatch[2];
456
+ const columnName = threePartMatch[3];
457
+ const afterOperator = threePartMatch[4];
458
+ const { jsonbPath, prefix } = parseJsonbPath(afterOperator);
459
+
460
+ return {
461
+ schema,
462
+ tableName,
463
+ jsonbColumn: columnName,
464
+ jsonbPath,
465
+ prefix
466
+ };
467
+ }
468
+
469
+ // Two-part JSONB pattern: table.column-> (or schema.column-> - backend determines)
470
+ const twoPartMatch = beforeCursor.match(/([\w]+)\.([\w]+)\s*->\s*(.*)$/);
471
+ if (twoPartMatch) {
472
+ const tableOrSchema = twoPartMatch[1];
473
+ const columnName = twoPartMatch[2];
474
+ const afterOperator = twoPartMatch[3];
475
+ const { jsonbPath, prefix } = parseJsonbPath(afterOperator);
476
+
457
477
  return {
458
478
  schemaOrTable: tableOrSchema,
459
479
  jsonbColumn: columnName,
460
480
  jsonbPath,
461
- prefix: currentPrefix
481
+ prefix
482
+ };
483
+ }
484
+
485
+ // One-part JSONB pattern: column-> (no table prefix)
486
+ const onePartMatch = beforeCursor.match(/([\w]+)\s*->\s*(.*)$/);
487
+ if (onePartMatch) {
488
+ const columnName = onePartMatch[1];
489
+ const afterOperator = onePartMatch[2];
490
+ const { jsonbPath, prefix } = parseJsonbPath(afterOperator);
491
+
492
+ return {
493
+ jsonbColumn: columnName,
494
+ jsonbPath,
495
+ prefix
462
496
  };
463
497
  }
464
498
  }
@@ -0,0 +1,155 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "id": "bbf7ca43",
7
+ "metadata": {},
8
+ "outputs": [],
9
+ "source": [
10
+ "%config SqlMagic.dsn_filename = \"connections.ini\""
11
+ ]
12
+ },
13
+ {
14
+ "cell_type": "code",
15
+ "execution_count": 2,
16
+ "id": "be51d56c",
17
+ "metadata": {},
18
+ "outputs": [
19
+ {
20
+ "data": {
21
+ "text/html": [
22
+ "<span style=\"None\">Tip: You may define configurations in /Users/benh/Projects/jl_db_completer/pyproject.toml or /Users/benh/.jupysql/config. </span>"
23
+ ],
24
+ "text/plain": [
25
+ "Tip: You may define configurations in /Users/benh/Projects/jl_db_completer/pyproject.toml or /Users/benh/.jupysql/config. "
26
+ ]
27
+ },
28
+ "metadata": {},
29
+ "output_type": "display_data"
30
+ },
31
+ {
32
+ "data": {
33
+ "text/html": [
34
+ "Please review our <a href='https://jupysql.ploomber.io/en/latest/api/configuration.html#loading-from-a-file'>configuration guideline</a>."
35
+ ],
36
+ "text/plain": [
37
+ "<IPython.core.display.HTML object>"
38
+ ]
39
+ },
40
+ "metadata": {},
41
+ "output_type": "display_data"
42
+ },
43
+ {
44
+ "data": {
45
+ "text/html": [
46
+ "<span style=\"None\">Did not find user configurations in /Users/benh/Projects/jl_db_completer/pyproject.toml.</span>"
47
+ ],
48
+ "text/plain": [
49
+ "Did not find user configurations in /Users/benh/Projects/jl_db_completer/pyproject.toml."
50
+ ]
51
+ },
52
+ "metadata": {},
53
+ "output_type": "display_data"
54
+ }
55
+ ],
56
+ "source": [
57
+ "%load_ext sql"
58
+ ]
59
+ },
60
+ {
61
+ "cell_type": "code",
62
+ "execution_count": 3,
63
+ "id": "36ec5be5",
64
+ "metadata": {},
65
+ "outputs": [
66
+ {
67
+ "data": {
68
+ "text/html": [
69
+ "<span style=\"None\">Connecting to &#x27;pg&#x27;</span>"
70
+ ],
71
+ "text/plain": [
72
+ "Connecting to 'pg'"
73
+ ]
74
+ },
75
+ "metadata": {},
76
+ "output_type": "display_data"
77
+ }
78
+ ],
79
+ "source": [
80
+ "%sql --section pg"
81
+ ]
82
+ },
83
+ {
84
+ "cell_type": "code",
85
+ "execution_count": 6,
86
+ "id": "ab7f4cca-0fba-41ae-8a94-13373849b09e",
87
+ "metadata": {},
88
+ "outputs": [
89
+ {
90
+ "data": {
91
+ "text/html": [
92
+ "<span style=\"None\">Running query in &#x27;pg&#x27;</span>"
93
+ ],
94
+ "text/plain": [
95
+ "Running query in 'pg'"
96
+ ]
97
+ },
98
+ "metadata": {},
99
+ "output_type": "display_data"
100
+ },
101
+ {
102
+ "name": "stderr",
103
+ "output_type": "stream",
104
+ "text": [
105
+ "RuntimeError: If using snippets, you may pass the --with argument explicitly.\n",
106
+ "For more details please refer: https://jupysql.ploomber.io/en/latest/compose.html#with-argument\n",
107
+ "\n",
108
+ "\n",
109
+ "Original error message from DB driver:\n",
110
+ "(psycopg2.errors.SyntaxError) syntax error at end of input\n",
111
+ "LINE 1: SELECT * FROM public.\n",
112
+ " ^\n",
113
+ "\n",
114
+ "[SQL: SELECT * FROM public.]\n",
115
+ "(Background on this error at: https://sqlalche.me/e/20/f405)\n",
116
+ "\n"
117
+ ]
118
+ }
119
+ ],
120
+ "source": [
121
+ "%%sql\n",
122
+ "SELECT content -> FROM public.reports"
123
+ ]
124
+ },
125
+ {
126
+ "cell_type": "code",
127
+ "execution_count": null,
128
+ "id": "782b36ad-d8c4-4dba-b4a8-9caf35d1b485",
129
+ "metadata": {},
130
+ "outputs": [],
131
+ "source": []
132
+ }
133
+ ],
134
+ "metadata": {
135
+ "kernelspec": {
136
+ "display_name": "Python 3 (ipykernel)",
137
+ "language": "python",
138
+ "name": "python3"
139
+ },
140
+ "language_info": {
141
+ "codemirror_mode": {
142
+ "name": "ipython",
143
+ "version": 3
144
+ },
145
+ "file_extension": ".py",
146
+ "mimetype": "text/x-python",
147
+ "name": "python",
148
+ "nbconvert_exporter": "python",
149
+ "pygments_lexer": "ipython3",
150
+ "version": "3.13.1"
151
+ }
152
+ },
153
+ "nbformat": 4,
154
+ "nbformat_minor": 5
155
+ }
@@ -1 +0,0 @@
1
- var _JUPYTERLAB;(()=>{"use strict";var e,r,t,n,o,a,i,u,l,f,s,d,p,c,h,v,b,g,m,y={246(e,r,t){var n={"./index":()=>t.e(171).then(()=>()=>t(171)),"./extension":()=>t.e(171).then(()=>()=>t(171)),"./style":()=>t.e(728).then(()=>()=>t(728))},o=(e,r)=>(t.R=r,r=t.o(n,e)?n[e]():Promise.resolve().then(()=>{throw new Error('Module "'+e+'" does not exist in container.')}),t.R=void 0,r),a=(e,r)=>{if(t.S){var n="default",o=t.S[n];if(o&&o!==e)throw new Error("Container initialization failed as it has already been initialized with a different share scope");return t.S[n]=e,t.I(n,r)}};t.d(r,{get:()=>o,init:()=>a})}},w={};function j(e){var r=w[e];if(void 0!==r)return r.exports;var t=w[e]={id:e,exports:{}};return y[e](t,t.exports,j),t.exports}j.m=y,j.c=w,j.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return j.d(r,{a:r}),r},j.d=(e,r)=>{for(var t in r)j.o(r,t)&&!j.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},j.f={},j.e=e=>Promise.all(Object.keys(j.f).reduce((r,t)=>(j.f[t](e,r),r),[])),j.u=e=>e+"."+{171:"d366980651e0db8d978c",728:"6552504d5b9b27551bc5"}[e]+".js?v="+{171:"d366980651e0db8d978c",728:"6552504d5b9b27551bc5"}[e],j.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),j.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},r="jl_db_comp:",j.l=(t,n,o,a)=>{if(e[t])e[t].push(n);else{var i,u;if(void 0!==o)for(var l=document.getElementsByTagName("script"),f=0;f<l.length;f++){var s=l[f];if(s.getAttribute("src")==t||s.getAttribute("data-webpack")==r+o){i=s;break}}i||(u=!0,(i=document.createElement("script")).charset="utf-8",j.nc&&i.setAttribute("nonce",j.nc),i.setAttribute("data-webpack",r+o),i.src=t),e[t]=[n];var d=(r,n)=>{i.onerror=i.onload=null,clearTimeout(p);var o=e[t];if(delete e[t],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach(e=>e(n)),r)return r(n)},p=setTimeout(d.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=d.bind(null,i.onerror),i.onload=d.bind(null,i.onload),u&&document.head.appendChild(i)}},j.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{j.S={};var e={},r={};j.I=(t,n)=>{n||(n=[]);var o=r[t];if(o||(o=r[t]={}),!(n.indexOf(o)>=0)){if(n.push(o),e[t])return e[t];j.o(j.S,t)||(j.S[t]={});var a=j.S[t],i="jl_db_comp",u=[];return"default"===t&&((e,r,t,n)=>{var o=a[e]=a[e]||{},u=o[r];(!u||!u.loaded&&(1!=!u.eager?n:i>u.from))&&(o[r]={get:()=>j.e(171).then(()=>()=>j(171)),from:i,eager:!1})})("jl_db_comp","0.1.9"),e[t]=u.length?Promise.all(u).then(()=>e[t]=1):1}}})(),(()=>{var e;j.g.importScripts&&(e=j.g.location+"");var r=j.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),j.p=e})(),t=e=>{var r=e=>e.split(".").map(e=>+e==e?+e:e),t=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(e),n=t[1]?r(t[1]):[];return t[2]&&(n.length++,n.push.apply(n,r(t[2]))),t[3]&&(n.push([]),n.push.apply(n,r(t[3]))),n},n=(e,r)=>{e=t(e),r=t(r);for(var n=0;;){if(n>=e.length)return n<r.length&&"u"!=(typeof r[n])[0];var o=e[n],a=(typeof o)[0];if(n>=r.length)return"u"==a;var i=r[n],u=(typeof i)[0];if(a!=u)return"o"==a&&"n"==u||"s"==u||"u"==a;if("o"!=a&&"u"!=a&&o!=i)return o<i;n++}},o=e=>{var r=e[0],t="";if(1===e.length)return"*";if(r+.5){t+=0==r?">=":-1==r?"<":1==r?"^":2==r?"~":r>0?"=":"!=";for(var n=1,a=1;a<e.length;a++)n--,t+="u"==(typeof(u=e[a]))[0]?"-":(n>0?".":"")+(n=2,u);return t}var i=[];for(a=1;a<e.length;a++){var u=e[a];i.push(0===u?"not("+l()+")":1===u?"("+l()+" || "+l()+")":2===u?i.pop()+" "+i.pop():o(u))}return l();function l(){return i.pop().replace(/^\((.+)\)$/,"$1")}},a=(e,r)=>{if(0 in e){r=t(r);var n=e[0],o=n<0;o&&(n=-n-1);for(var i=0,u=1,l=!0;;u++,i++){var f,s,d=u<e.length?(typeof e[u])[0]:"";if(i>=r.length||"o"==(s=(typeof(f=r[i]))[0]))return!l||("u"==d?u>n&&!o:""==d!=o);if("u"==s){if(!l||"u"!=d)return!1}else if(l)if(d==s)if(u<=n){if(f!=e[u])return!1}else{if(o?f>e[u]:f<e[u])return!1;f!=e[u]&&(l=!1)}else if("s"!=d&&"n"!=d){if(o||u<=n)return!1;l=!1,u--}else{if(u<=n||s<d!=o)return!1;l=!1}else"s"!=d&&"n"!=d&&(l=!1,u--)}}var p=[],c=p.pop.bind(p);for(i=1;i<e.length;i++){var h=e[i];p.push(1==h?c()|c():2==h?c()&c():h?a(h,r):!c())}return!!c()},i=(e,r)=>e&&j.o(e,r),u=e=>(e.loaded=1,e.get()),l=e=>Object.keys(e).reduce((r,t)=>(e[t].eager&&(r[t]=e[t]),r),{}),f=(e,r,t)=>{var o=t?l(e[r]):e[r];return Object.keys(o).reduce((e,r)=>!e||!o[e].loaded&&n(e,r)?r:e,0)},s=(e,r,t,n)=>"Unsatisfied version "+t+" from "+(t&&e[r][t].from)+" of shared singleton module "+r+" (required "+o(n)+")",d=e=>{throw new Error(e)},p=e=>{"undefined"!=typeof console&&console.warn&&console.warn(e)},c=(e,r,t)=>t?t():((e,r)=>d("Shared module "+r+" doesn't exist in shared scope "+e))(e,r),h=(e=>function(r,t,n,o,a){var i=j.I(r);return i&&i.then&&!n?i.then(e.bind(e,r,j.S[r],t,!1,o,a)):e(r,j.S[r],t,n,o,a)})((e,r,t,n,o,l)=>{if(!i(r,t))return c(e,t,l);var d=f(r,t,n);return a(o,d)||p(s(r,t,d,o)),u(r[t][d])}),v={},b={206:()=>h("default","@jupyterlab/completer",!1,[1,4,5,2]),428:()=>h("default","@jupyterlab/notebook",!1,[1,4,5,2]),469:()=>h("default","@jupyterlab/coreutils",!1,[1,6,5,2]),490:()=>h("default","@jupyterlab/settingregistry",!1,[1,4,5,2]),830:()=>h("default","@jupyterlab/services",!1,[1,7,5,2])},g={171:[206,428,469,490,830]},m={},j.f.consumes=(e,r)=>{j.o(g,e)&&g[e].forEach(e=>{if(j.o(v,e))return r.push(v[e]);if(!m[e]){var t=r=>{v[e]=0,j.m[e]=t=>{delete j.c[e],t.exports=r()}};m[e]=!0;var n=r=>{delete v[e],j.m[e]=t=>{throw delete j.c[e],r}};try{var o=b[e]();o.then?r.push(v[e]=o.then(t).catch(n)):t(o)}catch(e){n(e)}}})},(()=>{var e={248:0};j.f.j=(r,t)=>{var n=j.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var o=new Promise((t,o)=>n=e[r]=[t,o]);t.push(n[2]=o);var a=j.p+j.u(r),i=new Error;j.l(a,t=>{if(j.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var o=t&&("load"===t.type?"missing":t.type),a=t&&t.target&&t.target.src;i.message="Loading chunk "+r+" failed.\n("+o+": "+a+")",i.name="ChunkLoadError",i.type=o,i.request=a,n[1](i)}},"chunk-"+r,r)}};var r=(r,t)=>{var n,o,[a,i,u]=t,l=0;if(a.some(r=>0!==e[r])){for(n in i)j.o(i,n)&&(j.m[n]=i[n]);u&&u(j)}for(r&&r(t);l<a.length;l++)o=a[l],j.o(e,o)&&e[o]&&e[o][0](),e[o]=0},t=self.webpackChunkjl_db_comp=self.webpackChunkjl_db_comp||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),j.nc=void 0;var S=j(246);(_JUPYTERLAB=void 0===_JUPYTERLAB?{}:_JUPYTERLAB).jl_db_comp=S})();
@@ -1,241 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "code",
5
- "execution_count": 1,
6
- "id": "bbf7ca43",
7
- "metadata": {},
8
- "outputs": [],
9
- "source": [
10
- "%config SqlMagic.dsn_filename = \"connections.ini\""
11
- ]
12
- },
13
- {
14
- "cell_type": "code",
15
- "execution_count": 2,
16
- "id": "be51d56c",
17
- "metadata": {},
18
- "outputs": [
19
- {
20
- "data": {
21
- "text/html": [
22
- "<span style=\"None\">Tip: You may define configurations in /Users/benh/Projects/jl_db_completer/pyproject.toml or /Users/benh/.jupysql/config. </span>"
23
- ],
24
- "text/plain": [
25
- "Tip: You may define configurations in /Users/benh/Projects/jl_db_completer/pyproject.toml or /Users/benh/.jupysql/config. "
26
- ]
27
- },
28
- "metadata": {},
29
- "output_type": "display_data"
30
- },
31
- {
32
- "data": {
33
- "text/html": [
34
- "Please review our <a href='https://jupysql.ploomber.io/en/latest/api/configuration.html#loading-from-a-file'>configuration guideline</a>."
35
- ],
36
- "text/plain": [
37
- "<IPython.core.display.HTML object>"
38
- ]
39
- },
40
- "metadata": {},
41
- "output_type": "display_data"
42
- },
43
- {
44
- "data": {
45
- "text/html": [
46
- "<span style=\"None\">Did not find user configurations in /Users/benh/Projects/jl_db_completer/pyproject.toml.</span>"
47
- ],
48
- "text/plain": [
49
- "Did not find user configurations in /Users/benh/Projects/jl_db_completer/pyproject.toml."
50
- ]
51
- },
52
- "metadata": {},
53
- "output_type": "display_data"
54
- }
55
- ],
56
- "source": [
57
- "%load_ext sql"
58
- ]
59
- },
60
- {
61
- "cell_type": "code",
62
- "execution_count": 3,
63
- "id": "36ec5be5",
64
- "metadata": {},
65
- "outputs": [
66
- {
67
- "data": {
68
- "text/html": [
69
- "<span style=\"None\">Connecting to &#x27;mysql&#x27;</span>"
70
- ],
71
- "text/plain": [
72
- "Connecting to 'mysql'"
73
- ]
74
- },
75
- "metadata": {},
76
- "output_type": "display_data"
77
- }
78
- ],
79
- "source": [
80
- "%sql --section mysql"
81
- ]
82
- },
83
- {
84
- "cell_type": "code",
85
- "execution_count": 4,
86
- "id": "ab7f4cca-0fba-41ae-8a94-13373849b09e",
87
- "metadata": {},
88
- "outputs": [
89
- {
90
- "data": {
91
- "text/html": [
92
- "<span style=\"None\">Running query in &#x27;mysql&#x27;</span>"
93
- ],
94
- "text/plain": [
95
- "Running query in 'mysql'"
96
- ]
97
- },
98
- "metadata": {},
99
- "output_type": "display_data"
100
- },
101
- {
102
- "data": {
103
- "text/html": [
104
- "<span style=\"color: green\">5 rows affected.</span>"
105
- ],
106
- "text/plain": [
107
- "5 rows affected."
108
- ]
109
- },
110
- "metadata": {},
111
- "output_type": "display_data"
112
- },
113
- {
114
- "data": {
115
- "text/html": [
116
- "<table>\n",
117
- " <thead>\n",
118
- " <tr>\n",
119
- " <th>report_id</th>\n",
120
- " <th>patient_id</th>\n",
121
- " <th>encounter_id</th>\n",
122
- " <th>provider_id</th>\n",
123
- " <th>report_type</th>\n",
124
- " <th>report_date</th>\n",
125
- " <th>content</th>\n",
126
- " <th>status</th>\n",
127
- " <th>created_at</th>\n",
128
- " </tr>\n",
129
- " </thead>\n",
130
- " <tbody>\n",
131
- " <tr>\n",
132
- " <td>1</td>\n",
133
- " <td>1</td>\n",
134
- " <td>None</td>\n",
135
- " <td>1</td>\n",
136
- " <td>discharge</td>\n",
137
- " <td>2024-01-15 14:30:00</td>\n",
138
- " <td>{\"diet\": \"Regular diet as tolerated\", \"report_title\": \"Hospital Discharge Summary\", \"admission_date\": \"2024-01-10\", \"discharge_date\": \"2024-01-15\", \"hospital_course\": \"Patient admitted with RLQ pain, diagnosed with acute appendicitis. Underwent successful laparoscopic appendectomy. Post-operative course uncomplicated.\", \"admitting_diagnosis\": \"Acute appendicitis\", \"discharge_diagnosis\": [\"Acute appendicitis, status post appendectomy\", \"Hypertension, controlled\"], \"procedures_performed\": [{\"date\": \"2024-01-10\", \"name\": \"Laparoscopic appendectomy\", \"surgeon\": \"Dr. Michael Brown\"}], \"activity_restrictions\": [\"No heavy lifting for 4 weeks\", \"May return to work in 1-2 weeks\"], \"discharge_medications\": [{\"dose\": \"500mg\", \"name\": \"Acetaminophen\", \"duration\": \"7 days\", \"frequency\": \"every 6 hours as needed\"}, {\"dose\": \"10mg\", \"name\": \"Lisinopril\", \"duration\": \"ongoing\", \"frequency\": \"once daily\"}], \"follow_up_instructions\": [\"Surgical follow-up in 2 weeks\", \"Return if fever, increased pain, or wound drainage\"]}</td>\n",
139
- " <td>final</td>\n",
140
- " <td>2026-01-16 13:43:42</td>\n",
141
- " </tr>\n",
142
- " <tr>\n",
143
- " <td>2</td>\n",
144
- " <td>2</td>\n",
145
- " <td>None</td>\n",
146
- " <td>2</td>\n",
147
- " <td>surgical</td>\n",
148
- " <td>2024-02-20 11:00:00</td>\n",
149
- " <td>{\"findings\": {\"lad\": \"80% proximal stenosis\", \"lcx\": \"Minor irregularities\", \"rca\": \"30% mid stenosis\", \"left_main\": \"No significant stenosis\"}, \"specimens\": \"None\", \"anesthesia\": \"Local with conscious sedation\", \"indication\": \"Unstable angina, abnormal stress test\", \"report_title\": \"Operative Report\", \"complications\": \"None\", \"procedure_date\": \"2024-02-20\", \"procedure_name\": \"Cardiac catheterization with stent placement\", \"procedure_details\": \"Right femoral artery access obtained. Diagnostic angiography performed. Drug-eluting stent (3.0 x 18mm) deployed to proximal LAD with excellent angiographic result.\", \"post_procedure_plan\": [\"Dual antiplatelet therapy\", \"Cardiac rehab referral\", \"Follow-up echo in 4 weeks\"], \"estimated_blood_loss\": \"Minimal\"}</td>\n",
150
- " <td>final</td>\n",
151
- " <td>2026-01-16 13:43:42</td>\n",
152
- " </tr>\n",
153
- " <tr>\n",
154
- " <td>3</td>\n",
155
- " <td>3</td>\n",
156
- " <td>None</td>\n",
157
- " <td>1</td>\n",
158
- " <td>appointment</td>\n",
159
- " <td>2024-03-05 09:15:00</td>\n",
160
- " <td>{\"plan\": [{\"action\": \"Continue metformin 1000mg BID, recheck HbA1c in 3 months\", \"problem\": \"Diabetes\"}, {\"action\": \"Continue lisinopril 20mg daily\", \"problem\": \"Hypertension\"}, {\"action\": \"Flu vaccine administered today, due for colonoscopy\", \"problem\": \"Preventive care\"}], \"follow_up\": \"Return in 3 months\", \"assessment\": [\"Type 2 diabetes mellitus, controlled\", \"Hypertension, controlled\"], \"visit_type\": \"Follow-up\", \"report_title\": \"Office Visit Note\", \"physical_exam\": {\"vitals\": {\"bp\": \"128/78\", \"hr\": 72, \"temp\": \"98.6F\", \"weight\": \"185 lbs\"}, \"general\": \"Well-appearing, no acute distress\", \"extremities\": \"No edema, pulses intact, monofilament testing normal\", \"cardiovascular\": \"Regular rate and rhythm, no murmurs\"}, \"chief_complaint\": \"Diabetes management\", \"review_of_systems\": {\"respiratory\": \"No shortness of breath\", \"neurological\": \"No numbness or tingling in extremities\", \"cardiovascular\": \"No chest pain or palpitations\", \"constitutional\": \"No fever, weight stable\"}, \"history_of_present_illness\": \"Patient presents for routine diabetes follow-up. Reports good compliance with medications. Checking blood sugars 2x daily, ranging 110-140 fasting. No hypoglycemic episodes.\"}</td>\n",
161
- " <td>final</td>\n",
162
- " <td>2026-01-16 13:43:42</td>\n",
163
- " </tr>\n",
164
- " <tr>\n",
165
- " <td>4</td>\n",
166
- " <td>1</td>\n",
167
- " <td>None</td>\n",
168
- " <td>2</td>\n",
169
- " <td>diagnostic</td>\n",
170
- " <td>2024-01-08 16:45:00</td>\n",
171
- " <td>{\"findings\": {\"left_atrium\": {\"size\": \"Normal\"}, \"pericardium\": \"No effusion\", \"aortic_valve\": {\"stenosis\": \"None\", \"structure\": \"Trileaflet, normal\", \"regurgitation\": \"Trace\"}, \"mitral_valve\": {\"stenosis\": \"None\", \"structure\": \"Normal\", \"regurgitation\": \"Mild\"}, \"right_atrium\": {\"size\": \"Normal\"}, \"left_ventricle\": {\"size\": \"Normal\", \"wall_motion\": \"No regional wall motion abnormalities\", \"wall_thickness\": \"Normal\", \"ejection_fraction\": \"60-65%\", \"systolic_function\": \"Normal\"}, \"right_ventricle\": {\"size\": \"Normal\", \"function\": \"Normal\"}}, \"technique\": \"Complete 2D and Doppler echocardiogram\", \"impression\": [\"Normal left ventricular size and systolic function\", \"Mild mitral regurgitation\", \"No significant valvular abnormalities\"], \"indication\": \"Chest pain, rule out cardiac etiology\", \"study_date\": \"2024-01-08\", \"report_title\": \"Echocardiogram Report\", \"recommendations\": \"No further cardiac workup needed at this time\"}</td>\n",
172
- " <td>final</td>\n",
173
- " <td>2026-01-16 13:43:42</td>\n",
174
- " </tr>\n",
175
- " <tr>\n",
176
- " <td>5</td>\n",
177
- " <td>2</td>\n",
178
- " <td>None</td>\n",
179
- " <td>1</td>\n",
180
- " <td>consultation</td>\n",
181
- " <td>2024-02-15 10:30:00</td>\n",
182
- " <td>{\"assessment\": \"Unstable angina, high suspicion for coronary artery disease\", \"report_title\": \"Cardiology Consultation\", \"recommendations\": [\"Admit for observation\", \"Start heparin drip\", \"Add aspirin 81mg daily\", \"Cardiac catheterization in AM\"], \"consultation_date\": \"2024-02-15\", \"diagnostic_studies\": {\"bnp\": \"120 pg/mL\", \"ecg\": \"Sinus rhythm, T-wave inversions in V1-V3\", \"troponin\": \"Negative x2\"}, \"current_medications\": [\"Lisinopril 10mg daily\", \"Atorvastatin 20mg daily\"], \"referring_physician\": \"Dr. Sarah Williams\", \"past_medical_history\": [\"Hypertension\", \"Hyperlipidemia\", \"Family history of CAD\"], \"physical_examination\": {\"lungs\": \"Clear to auscultation\", \"general\": \"Anxious-appearing female in no acute distress\", \"cardiovascular\": \"Regular rhythm, S4 gallop present, no murmurs\"}, \"reason_for_consultation\": \"Evaluation of chest pain and abnormal ECG\", \"history_of_present_illness\": \"55-year-old female with 2-week history of exertional chest pressure. Pain is substernal, radiates to left arm, relieved by rest.\"}</td>\n",
183
- " <td>final</td>\n",
184
- " <td>2026-01-16 13:43:42</td>\n",
185
- " </tr>\n",
186
- " </tbody>\n",
187
- "</table>"
188
- ],
189
- "text/plain": [
190
- "+-----------+------------+--------------+-------------+--------------+---------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+---------------------+\n",
191
- "| report_id | patient_id | encounter_id | provider_id | report_type | report_date | content | status | created_at |\n",
192
- "+-----------+------------+--------------+-------------+--------------+---------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+---------------------+\n",
193
- "| 1 | 1 | None | 1 | discharge | 2024-01-15 14:30:00 | {\"diet\": \"Regular diet as tolerated\", \"report_title\": \"Hospital Discharge Summary\", \"admission_date\": \"2024-01-10\", \"discharge_date\": \"2024-01-15\", \"hospital_course\": \"Patient admitted with RLQ pain, diagnosed with acute appendicitis. Underwent successful laparoscopic appendectomy. Post-operative course uncomplicated.\", \"admitting_diagnosis\": \"Acute appendicitis\", \"discharge_diagnosis\": [\"Acute appendicitis, status post appendectomy\", \"Hypertension, controlled\"], \"procedures_performed\": [{\"date\": \"2024-01-10\", \"name\": \"Laparoscopic appendectomy\", \"surgeon\": \"Dr. Michael Brown\"}], \"activity_restrictions\": [\"No heavy lifting for 4 weeks\", \"May return to work in 1-2 weeks\"], \"discharge_medications\": [{\"dose\": \"500mg\", \"name\": \"Acetaminophen\", \"duration\": \"7 days\", \"frequency\": \"every 6 hours as needed\"}, {\"dose\": \"10mg\", \"name\": \"Lisinopril\", \"duration\": \"ongoing\", \"frequency\": \"once daily\"}], \"follow_up_instructions\": [\"Surgical follow-up in 2 weeks\", \"Return if fever, increased pain, or wound drainage\"]} | final | 2026-01-16 13:43:42 |\n",
194
- "| 2 | 2 | None | 2 | surgical | 2024-02-20 11:00:00 | {\"findings\": {\"lad\": \"80% proximal stenosis\", \"lcx\": \"Minor irregularities\", \"rca\": \"30% mid stenosis\", \"left_main\": \"No significant stenosis\"}, \"specimens\": \"None\", \"anesthesia\": \"Local with conscious sedation\", \"indication\": \"Unstable angina, abnormal stress test\", \"report_title\": \"Operative Report\", \"complications\": \"None\", \"procedure_date\": \"2024-02-20\", \"procedure_name\": \"Cardiac catheterization with stent placement\", \"procedure_details\": \"Right femoral artery access obtained. Diagnostic angiography performed. Drug-eluting stent (3.0 x 18mm) deployed to proximal LAD with excellent angiographic result.\", \"post_procedure_plan\": [\"Dual antiplatelet therapy\", \"Cardiac rehab referral\", \"Follow-up echo in 4 weeks\"], \"estimated_blood_loss\": \"Minimal\"} | final | 2026-01-16 13:43:42 |\n",
195
- "| 3 | 3 | None | 1 | appointment | 2024-03-05 09:15:00 | {\"plan\": [{\"action\": \"Continue metformin 1000mg BID, recheck HbA1c in 3 months\", \"problem\": \"Diabetes\"}, {\"action\": \"Continue lisinopril 20mg daily\", \"problem\": \"Hypertension\"}, {\"action\": \"Flu vaccine administered today, due for colonoscopy\", \"problem\": \"Preventive care\"}], \"follow_up\": \"Return in 3 months\", \"assessment\": [\"Type 2 diabetes mellitus, controlled\", \"Hypertension, controlled\"], \"visit_type\": \"Follow-up\", \"report_title\": \"Office Visit Note\", \"physical_exam\": {\"vitals\": {\"bp\": \"128/78\", \"hr\": 72, \"temp\": \"98.6F\", \"weight\": \"185 lbs\"}, \"general\": \"Well-appearing, no acute distress\", \"extremities\": \"No edema, pulses intact, monofilament testing normal\", \"cardiovascular\": \"Regular rate and rhythm, no murmurs\"}, \"chief_complaint\": \"Diabetes management\", \"review_of_systems\": {\"respiratory\": \"No shortness of breath\", \"neurological\": \"No numbness or tingling in extremities\", \"cardiovascular\": \"No chest pain or palpitations\", \"constitutional\": \"No fever, weight stable\"}, \"history_of_present_illness\": \"Patient presents for routine diabetes follow-up. Reports good compliance with medications. Checking blood sugars 2x daily, ranging 110-140 fasting. No hypoglycemic episodes.\"} | final | 2026-01-16 13:43:42 |\n",
196
- "| 4 | 1 | None | 2 | diagnostic | 2024-01-08 16:45:00 | {\"findings\": {\"left_atrium\": {\"size\": \"Normal\"}, \"pericardium\": \"No effusion\", \"aortic_valve\": {\"stenosis\": \"None\", \"structure\": \"Trileaflet, normal\", \"regurgitation\": \"Trace\"}, \"mitral_valve\": {\"stenosis\": \"None\", \"structure\": \"Normal\", \"regurgitation\": \"Mild\"}, \"right_atrium\": {\"size\": \"Normal\"}, \"left_ventricle\": {\"size\": \"Normal\", \"wall_motion\": \"No regional wall motion abnormalities\", \"wall_thickness\": \"Normal\", \"ejection_fraction\": \"60-65%\", \"systolic_function\": \"Normal\"}, \"right_ventricle\": {\"size\": \"Normal\", \"function\": \"Normal\"}}, \"technique\": \"Complete 2D and Doppler echocardiogram\", \"impression\": [\"Normal left ventricular size and systolic function\", \"Mild mitral regurgitation\", \"No significant valvular abnormalities\"], \"indication\": \"Chest pain, rule out cardiac etiology\", \"study_date\": \"2024-01-08\", \"report_title\": \"Echocardiogram Report\", \"recommendations\": \"No further cardiac workup needed at this time\"} | final | 2026-01-16 13:43:42 |\n",
197
- "| 5 | 2 | None | 1 | consultation | 2024-02-15 10:30:00 | {\"assessment\": \"Unstable angina, high suspicion for coronary artery disease\", \"report_title\": \"Cardiology Consultation\", \"recommendations\": [\"Admit for observation\", \"Start heparin drip\", \"Add aspirin 81mg daily\", \"Cardiac catheterization in AM\"], \"consultation_date\": \"2024-02-15\", \"diagnostic_studies\": {\"bnp\": \"120 pg/mL\", \"ecg\": \"Sinus rhythm, T-wave inversions in V1-V3\", \"troponin\": \"Negative x2\"}, \"current_medications\": [\"Lisinopril 10mg daily\", \"Atorvastatin 20mg daily\"], \"referring_physician\": \"Dr. Sarah Williams\", \"past_medical_history\": [\"Hypertension\", \"Hyperlipidemia\", \"Family history of CAD\"], \"physical_examination\": {\"lungs\": \"Clear to auscultation\", \"general\": \"Anxious-appearing female in no acute distress\", \"cardiovascular\": \"Regular rhythm, S4 gallop present, no murmurs\"}, \"reason_for_consultation\": \"Evaluation of chest pain and abnormal ECG\", \"history_of_present_illness\": \"55-year-old female with 2-week history of exertional chest pressure. Pain is substernal, radiates to left arm, relieved by rest.\"} | final | 2026-01-16 13:43:42 |\n",
198
- "+-----------+------------+--------------+-------------+--------------+---------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+---------------------+"
199
- ]
200
- },
201
- "execution_count": 4,
202
- "metadata": {},
203
- "output_type": "execute_result"
204
- }
205
- ],
206
- "source": [
207
- "%%sql\n",
208
- "SELECT * FROM "
209
- ]
210
- },
211
- {
212
- "cell_type": "code",
213
- "execution_count": null,
214
- "id": "782b36ad-d8c4-4dba-b4a8-9caf35d1b485",
215
- "metadata": {},
216
- "outputs": [],
217
- "source": []
218
- }
219
- ],
220
- "metadata": {
221
- "kernelspec": {
222
- "display_name": "Python 3 (ipykernel)",
223
- "language": "python",
224
- "name": "python3"
225
- },
226
- "language_info": {
227
- "codemirror_mode": {
228
- "name": "ipython",
229
- "version": 3
230
- },
231
- "file_extension": ".py",
232
- "mimetype": "text/x-python",
233
- "name": "python",
234
- "nbconvert_exporter": "python",
235
- "pygments_lexer": "ipython3",
236
- "version": "3.13.1"
237
- }
238
- },
239
- "nbformat": 4,
240
- "nbformat_minor": 5
241
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes