s3rds 0.3.1__tar.gz → 0.3.2__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.
- {s3rds-0.3.1 → s3rds-0.3.2}/PKG-INFO +2 -2
- {s3rds-0.3.1 → s3rds-0.3.2}/README.md +1 -1
- {s3rds-0.3.1 → s3rds-0.3.2}/pyproject.toml +1 -1
- {s3rds-0.3.1 → s3rds-0.3.2}/s3rds/server/index.html +30 -18
- {s3rds-0.3.1 → s3rds-0.3.2}/s3rds/sqlite/__init__.py +1 -1
- {s3rds-0.3.1 → s3rds-0.3.2}/s3rds.egg-info/PKG-INFO +2 -2
- {s3rds-0.3.1 → s3rds-0.3.2}/s3rds/__init__.py +0 -0
- {s3rds-0.3.1 → s3rds-0.3.2}/s3rds/psycopg2/__init__.py +0 -0
- {s3rds-0.3.1 → s3rds-0.3.2}/s3rds/psycopg2/errors.py +0 -0
- {s3rds-0.3.1 → s3rds-0.3.2}/s3rds/psycopg2/extensions.py +0 -0
- {s3rds-0.3.1 → s3rds-0.3.2}/s3rds/psycopg2/extras.py +0 -0
- {s3rds-0.3.1 → s3rds-0.3.2}/s3rds/pymysql.py +0 -0
- {s3rds-0.3.1 → s3rds-0.3.2}/s3rds/server/__init__.py +0 -0
- {s3rds-0.3.1 → s3rds-0.3.2}/s3rds/server/lambda_function.py +0 -0
- {s3rds-0.3.1 → s3rds-0.3.2}/s3rds/server/s3_sqlite.py +0 -0
- {s3rds-0.3.1 → s3rds-0.3.2}/s3rds/sqlite/base.py +0 -0
- {s3rds-0.3.1 → s3rds-0.3.2}/s3rds.egg-info/SOURCES.txt +0 -0
- {s3rds-0.3.1 → s3rds-0.3.2}/s3rds.egg-info/dependency_links.txt +0 -0
- {s3rds-0.3.1 → s3rds-0.3.2}/s3rds.egg-info/entry_points.txt +0 -0
- {s3rds-0.3.1 → s3rds-0.3.2}/s3rds.egg-info/requires.txt +0 -0
- {s3rds-0.3.1 → s3rds-0.3.2}/s3rds.egg-info/top_level.txt +0 -0
- {s3rds-0.3.1 → s3rds-0.3.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: s3rds
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: A truly serverless RDS on your own AWS account: Lambda URL endpoint, SQLite on S3, ≈ $0 when idle. Drivers named after the standard clients: s3rds.sqlite, s3rds.pymysql, s3rds.psycopg2; SQLAlchemy via sqlite+s3rds://, Django via ENGINE s3rds.sqlite.
|
|
5
5
|
Author: Frank Zhang
|
|
6
6
|
License: MIT
|
|
@@ -53,7 +53,7 @@ backwards (`import pymysql`, `import psycopg2`, `mysql+pymysql://`, `django.db.b
|
|
|
53
53
|
### The server: deploy once, ≈ $0 when idle
|
|
54
54
|
|
|
55
55
|
You need an s3rds server in your own AWS account — a Lambda Function URL and an S3 bucket, nothing running
|
|
56
|
-
while nobody uses it. Deploy it once with Terraform
|
|
56
|
+
while nobody uses it. Deploy it once with Terraform from the
|
|
57
57
|
[main repository](https://github.com/cloudformer/s3rds#quick-start). Same as any driver needs its database.
|
|
58
58
|
|
|
59
59
|
**Python drivers for [s3rds](https://github.com/cloudformer/s3rds) — a truly serverless RDS:
|
|
@@ -20,7 +20,7 @@ backwards (`import pymysql`, `import psycopg2`, `mysql+pymysql://`, `django.db.b
|
|
|
20
20
|
### The server: deploy once, ≈ $0 when idle
|
|
21
21
|
|
|
22
22
|
You need an s3rds server in your own AWS account — a Lambda Function URL and an S3 bucket, nothing running
|
|
23
|
-
while nobody uses it. Deploy it once with Terraform
|
|
23
|
+
while nobody uses it. Deploy it once with Terraform from the
|
|
24
24
|
[main repository](https://github.com/cloudformer/s3rds#quick-start). Same as any driver needs its database.
|
|
25
25
|
|
|
26
26
|
**Python drivers for [s3rds](https://github.com/cloudformer/s3rds) — a truly serverless RDS:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "s3rds"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.2"
|
|
8
8
|
description = "A truly serverless RDS on your own AWS account: Lambda URL endpoint, SQLite on S3, ≈ $0 when idle. Drivers named after the standard clients: s3rds.sqlite, s3rds.pymysql, s3rds.psycopg2; SQLAlchemy via sqlite+s3rds://, Django via ENGINE s3rds.sqlite."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -14,7 +14,7 @@ body {
|
|
|
14
14
|
padding: 40px 20px;
|
|
15
15
|
}
|
|
16
16
|
.container {
|
|
17
|
-
max-width:
|
|
17
|
+
max-width: 1440px;
|
|
18
18
|
margin: 0 auto;
|
|
19
19
|
background: white;
|
|
20
20
|
border-radius: 15px;
|
|
@@ -92,19 +92,28 @@ h1 { color: #333; margin-bottom: 10px; }
|
|
|
92
92
|
font-size: 16px; font-weight: 600; color: #4b5563; margin: 20px 0 10px 0;
|
|
93
93
|
display: flex; align-items: center; gap: 10px;
|
|
94
94
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
/* result grid: every column visible at once (long text wraps inside its cell, nothing is cut off);
|
|
96
|
+
a very wide or tall result scrolls inside its own frame with the header pinned */
|
|
97
|
+
.grid-wrap {
|
|
98
|
+
overflow: auto; max-height: 60vh; margin-bottom: 20px;
|
|
99
|
+
border: 1px solid #d1d5db; border-radius: 8px; background: white;
|
|
98
100
|
}
|
|
101
|
+
.grid-wrap::-webkit-scrollbar { width: 10px; height: 10px; }
|
|
102
|
+
.grid-wrap::-webkit-scrollbar-thumb { background: #c4c9d2; border-radius: 5px; border: 2px solid white; }
|
|
103
|
+
.grid-wrap::-webkit-scrollbar-corner { background: white; }
|
|
104
|
+
table { min-width: 100%; border-collapse: separate; border-spacing: 0; background: white; }
|
|
99
105
|
th {
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
position: sticky; top: 0; z-index: 1;
|
|
107
|
+
background: #374151; color: white; padding: 9px 12px; text-align: left;
|
|
108
|
+
font-weight: 600; font-size: 13px; white-space: nowrap;
|
|
102
109
|
}
|
|
103
110
|
td {
|
|
104
|
-
padding:
|
|
105
|
-
font-size:
|
|
106
|
-
overflow:
|
|
111
|
+
padding: 7px 12px; border-bottom: 1px solid #eef0f3; border-right: 1px solid #f3f4f6;
|
|
112
|
+
font-size: 13px; color: #374151; max-width: 280px; font-variant-numeric: tabular-nums;
|
|
113
|
+
white-space: normal; overflow-wrap: anywhere; vertical-align: top; line-height: 1.45;
|
|
107
114
|
}
|
|
115
|
+
td.rownum, th.rownum { color: #9ca3af; text-align: right; min-width: 36px; background: #f9fafb; }
|
|
116
|
+
th.rownum { background: #374151; color: #9ca3af; }
|
|
108
117
|
tr:last-child td { border-bottom: none; }
|
|
109
118
|
tr:hover td { background: #f9fafb; }
|
|
110
119
|
td.null { color: #9ca3af; font-style: italic; }
|
|
@@ -198,7 +207,7 @@ dialog .form-grid { grid-template-columns: 1fr; }
|
|
|
198
207
|
<button class="btn btn-ghost btn-small" id="togglelog">history</button>
|
|
199
208
|
</div>
|
|
200
209
|
<div class="log" id="log"></div>
|
|
201
|
-
<div id="sqlout" style="margin-top:12px" hidden><table id="sqlgrid"></table></div>
|
|
210
|
+
<div id="sqlout" class="grid-wrap" style="margin-top:12px" hidden><table id="sqlgrid"></table></div>
|
|
202
211
|
</div>
|
|
203
212
|
|
|
204
213
|
<div id="main"></div>
|
|
@@ -306,6 +315,11 @@ function rowsLine(d){ return `${d.rows.length} rows retrieved ${timing(d)}`; }
|
|
|
306
315
|
function doneLine(d){ return `${d.rowcount >= 0 ? d.rowcount + ' rows affected' : 'completed'} ${timing(d)}`; }
|
|
307
316
|
function esc(s){ return String(s).replace(/[&<>"]/g,
|
|
308
317
|
c => ({'&':'&','<':'<','>':'>','"':'"'}[c])); }
|
|
318
|
+
function cell(v){
|
|
319
|
+
if (v === null) return '<td class="null">NULL</td>';
|
|
320
|
+
const t = typeof v === 'object' ? JSON.stringify(v) : String(v);
|
|
321
|
+
return `<td title="${esc(t)}">${esc(t)}</td>`;
|
|
322
|
+
}
|
|
309
323
|
function sqlStr(v){ return v === null ? 'NULL' : "'" + String(v).replace(/'/g, "''") + "'"; }
|
|
310
324
|
function friendly(m){
|
|
311
325
|
if (/incomplete input/.test(m))
|
|
@@ -433,8 +447,7 @@ function render(){
|
|
|
433
447
|
const dataHead = '<tr>' + state.columns.map(c => `<th>${esc(c)}</th>`).join('')
|
|
434
448
|
+ (hasRowid ? '<th>actions</th>' : '') + '</tr>';
|
|
435
449
|
const dataRows = state.rows.map((r, i) =>
|
|
436
|
-
`<tr data-i="${i}">` + r.map(
|
|
437
|
-
? '<td class="null">NULL</td>' : `<td>${esc(v)}</td>`).join('')
|
|
450
|
+
`<tr data-i="${i}">` + r.map(cell).join('')
|
|
438
451
|
+ (hasRowid
|
|
439
452
|
? `<td style="white-space:nowrap"><button class="btn btn-ghost btn-small" onclick="editRow(${i})">edit</button>
|
|
440
453
|
<button class="btn-danger" onclick="delRow(${i})">🗑 delete</button></td>` : '')
|
|
@@ -450,10 +463,10 @@ function render(){
|
|
|
450
463
|
<div class="section-title">Structure
|
|
451
464
|
<button class="btn btn-secondary btn-small" id="addcol">+ Add column</button>
|
|
452
465
|
</div>
|
|
453
|
-
<table>
|
|
466
|
+
<div class="grid-wrap"><table>
|
|
454
467
|
<thead><tr><th>Field</th><th>Type</th><th>Null</th><th>Key</th><th>Default</th><th>Extra</th><th>actions</th></tr></thead>
|
|
455
468
|
<tbody>${structRows}</tbody>
|
|
456
|
-
</table>
|
|
469
|
+
</table></div>
|
|
457
470
|
|
|
458
471
|
<div class="add-form">
|
|
459
472
|
<h3>➕ Insert a row into ${esc(state.table)}</h3>
|
|
@@ -467,7 +480,7 @@ function render(){
|
|
|
467
480
|
${state.ms !== undefined ? `<span class="hint">${state.ms} ms · ${state.s3}</span>` : ''}
|
|
468
481
|
</div>
|
|
469
482
|
${state.rows.length
|
|
470
|
-
? `<table id="grid"><thead>${dataHead}</thead><tbody>${dataRows}</tbody></table>`
|
|
483
|
+
? `<div class="grid-wrap"><table id="grid"><thead>${dataHead}</thead><tbody>${dataRows}</tbody></table></div>`
|
|
471
484
|
: '<div class="empty">No rows yet — insert the first one with the form above</div>'}
|
|
472
485
|
|
|
473
486
|
<div class="pagination">
|
|
@@ -598,9 +611,8 @@ async function runSql(){
|
|
|
598
611
|
const out = $('#sqlout'), t = $('#sqlgrid');
|
|
599
612
|
if (d.columns.length){
|
|
600
613
|
out.hidden = false;
|
|
601
|
-
t.innerHTML = '<thead><tr>' + d.columns.map(c => `<th>${esc(c)}</th>`).join('') + '</tr></thead><tbody>'
|
|
602
|
-
+ d.rows.map(r =>
|
|
603
|
-
? '<td class="null">NULL</td>' : `<td>${esc(v)}</td>`).join('') + '</tr>').join('') + '</tbody>';
|
|
614
|
+
t.innerHTML = '<thead><tr><th class="rownum">#</th>' + d.columns.map(c => `<th>${esc(c)}</th>`).join('') + '</tr></thead><tbody>'
|
|
615
|
+
+ d.rows.map((r, i) => `<tr><td class="rownum">${i + 1}</td>` + r.map(cell).join('') + '</tr>').join('') + '</tbody>';
|
|
604
616
|
msg(rowsLine(d), true);
|
|
605
617
|
} else {
|
|
606
618
|
t.innerHTML = ''; out.hidden = true;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: s3rds
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: A truly serverless RDS on your own AWS account: Lambda URL endpoint, SQLite on S3, ≈ $0 when idle. Drivers named after the standard clients: s3rds.sqlite, s3rds.pymysql, s3rds.psycopg2; SQLAlchemy via sqlite+s3rds://, Django via ENGINE s3rds.sqlite.
|
|
5
5
|
Author: Frank Zhang
|
|
6
6
|
License: MIT
|
|
@@ -53,7 +53,7 @@ backwards (`import pymysql`, `import psycopg2`, `mysql+pymysql://`, `django.db.b
|
|
|
53
53
|
### The server: deploy once, ≈ $0 when idle
|
|
54
54
|
|
|
55
55
|
You need an s3rds server in your own AWS account — a Lambda Function URL and an S3 bucket, nothing running
|
|
56
|
-
while nobody uses it. Deploy it once with Terraform
|
|
56
|
+
while nobody uses it. Deploy it once with Terraform from the
|
|
57
57
|
[main repository](https://github.com/cloudformer/s3rds#quick-start). Same as any driver needs its database.
|
|
58
58
|
|
|
59
59
|
**Python drivers for [s3rds](https://github.com/cloudformer/s3rds) — a truly serverless RDS:
|
|
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
|