framework-py 0.1.0.dev0__py3-none-any.whl
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.
- framework/__init__.py +250 -0
- framework/__main__.py +89 -0
- framework/_assets/hooks/pre-commit +59 -0
- framework/_assets/init.sql +63 -0
- framework/_assets/schema/layer.v1.json +605 -0
- framework/_assets/schema/layers.v1.json +791 -0
- framework/_assets/schema/spec.v1.json +604 -0
- framework/_log.py +29 -0
- framework/_paths.py +45 -0
- framework/_secretservice.py +69 -0
- framework/_time.py +11 -0
- framework/_wincred.py +105 -0
- framework/_yaml.py +90 -0
- framework/ai.py +204 -0
- framework/bootstrap.py +206 -0
- framework/cache.py +335 -0
- framework/catalog.py +193 -0
- framework/cloud.py +899 -0
- framework/config_home.py +194 -0
- framework/connections.py +442 -0
- framework/console.py +41 -0
- framework/create.py +579 -0
- framework/data.py +519 -0
- framework/db.py +222 -0
- framework/dotenv.py +79 -0
- framework/errors.py +39 -0
- framework/global_config.py +238 -0
- framework/hooks.py +364 -0
- framework/integrity.py +22 -0
- framework/notebooks.py +384 -0
- framework/outputs.py +324 -0
- framework/packages.py +276 -0
- framework/project.py +52 -0
- framework/py.typed +0 -0
- framework/quarto.py +163 -0
- framework/scaffold.py +269 -0
- framework/scratch.py +108 -0
- framework/security.py +646 -0
- framework/settings.py +439 -0
- framework/spec/__init__.py +0 -0
- framework/spec/check.py +211 -0
- framework/spec/merge.py +195 -0
- framework/spec/resolve.py +254 -0
- framework/storage.py +516 -0
- framework/templates/defaults.yml +144 -0
- framework/templates/gitignore/course +120 -0
- framework/templates/gitignore/presentation +114 -0
- framework/templates/gitignore/project +108 -0
- framework/templates/gitignore/sensitive +139 -0
- framework/templates/skills/framework-data/SKILL.md +47 -0
- framework/templates/skills/framework-outputs/SKILL.md +68 -0
- framework/templates/skills/framework-packages/SKILL.md +33 -0
- framework/templates/skills/framework-sensitive-data/SKILL.md +38 -0
- framework/templates/skills/framework-workflow/SKILL.md +58 -0
- framework/templates/stubs/notebook-default.ipynb +34 -0
- framework/templates/stubs/notebook-default.qmd +43 -0
- framework/templates/stubs/notebook-minimal.qmd +15 -0
- framework/templates/stubs/notebook-revealjs.qmd +34 -0
- framework/templates/stubs/script-default.py +18 -0
- framework_py-0.1.0.dev0.dist-info/METADATA +111 -0
- framework_py-0.1.0.dev0.dist-info/RECORD +63 -0
- framework_py-0.1.0.dev0.dist-info/WHEEL +4 -0
- framework_py-0.1.0.dev0.dist-info/licenses/LICENSE +21 -0
framework/__init__.py
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"""Framework: structured data science projects.
|
|
2
|
+
|
|
3
|
+
Import it as ``import framework as fw``. The functions here match the R
|
|
4
|
+
package's names, so the same documentation and skills apply in both
|
|
5
|
+
languages.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
11
|
+
|
|
12
|
+
from framework._time import now
|
|
13
|
+
from framework.ai import ai_skills_update
|
|
14
|
+
from framework.bootstrap import BootstrapResult, bootstrap
|
|
15
|
+
from framework.cache import (
|
|
16
|
+
cache,
|
|
17
|
+
cache_flush,
|
|
18
|
+
cache_forget,
|
|
19
|
+
cache_get,
|
|
20
|
+
cache_list,
|
|
21
|
+
cache_remember,
|
|
22
|
+
)
|
|
23
|
+
from framework.catalog import DataInfo, data_info, data_list
|
|
24
|
+
from framework.cloud import (
|
|
25
|
+
CloudError,
|
|
26
|
+
cloud_login,
|
|
27
|
+
cloud_logout,
|
|
28
|
+
cloud_settings,
|
|
29
|
+
cloud_status,
|
|
30
|
+
cloud_sync,
|
|
31
|
+
data_verify,
|
|
32
|
+
ledger_list,
|
|
33
|
+
ledger_push,
|
|
34
|
+
)
|
|
35
|
+
from framework.config_home import (
|
|
36
|
+
config_dir,
|
|
37
|
+
config_sync,
|
|
38
|
+
global_settings,
|
|
39
|
+
project_list,
|
|
40
|
+
project_register,
|
|
41
|
+
project_unregister,
|
|
42
|
+
)
|
|
43
|
+
from framework.connections import (
|
|
44
|
+
Connection,
|
|
45
|
+
connections_list,
|
|
46
|
+
db_connect,
|
|
47
|
+
db_drivers_status,
|
|
48
|
+
db_execute,
|
|
49
|
+
db_list,
|
|
50
|
+
db_query,
|
|
51
|
+
db_transaction,
|
|
52
|
+
)
|
|
53
|
+
from framework.console import CapturedOutput, capture_output
|
|
54
|
+
from framework.create import (
|
|
55
|
+
new,
|
|
56
|
+
project_add_directory,
|
|
57
|
+
project_create,
|
|
58
|
+
project_create_from_layers,
|
|
59
|
+
)
|
|
60
|
+
from framework.data import data_add, data_read, data_save
|
|
61
|
+
from framework.errors import (
|
|
62
|
+
CacheWarning,
|
|
63
|
+
DataChangedWarning,
|
|
64
|
+
DataNotFoundError,
|
|
65
|
+
FrameworkError,
|
|
66
|
+
FrameworkWarning,
|
|
67
|
+
IntegrityError,
|
|
68
|
+
ProjectNotFoundError,
|
|
69
|
+
SettingsError,
|
|
70
|
+
UnsupportedFormatError,
|
|
71
|
+
)
|
|
72
|
+
from framework.global_config import (
|
|
73
|
+
configure_global,
|
|
74
|
+
framework_template_path,
|
|
75
|
+
load_settings_catalog,
|
|
76
|
+
read_framework_template,
|
|
77
|
+
reset_framework_template,
|
|
78
|
+
write_framework_template,
|
|
79
|
+
)
|
|
80
|
+
from framework.hooks import (
|
|
81
|
+
git_hooks_disable,
|
|
82
|
+
git_hooks_enable,
|
|
83
|
+
git_hooks_install,
|
|
84
|
+
git_hooks_list,
|
|
85
|
+
git_hooks_uninstall,
|
|
86
|
+
)
|
|
87
|
+
from framework.notebooks import (
|
|
88
|
+
make_notebook,
|
|
89
|
+
make_presentation,
|
|
90
|
+
make_qmd,
|
|
91
|
+
make_revealjs,
|
|
92
|
+
make_script,
|
|
93
|
+
stubs_list,
|
|
94
|
+
stubs_path,
|
|
95
|
+
stubs_publish,
|
|
96
|
+
)
|
|
97
|
+
from framework.outputs import (
|
|
98
|
+
result_list,
|
|
99
|
+
save_figure,
|
|
100
|
+
save_model,
|
|
101
|
+
save_notebook,
|
|
102
|
+
save_report,
|
|
103
|
+
save_table,
|
|
104
|
+
)
|
|
105
|
+
from framework.packages import (
|
|
106
|
+
PackagesStatus,
|
|
107
|
+
package_add,
|
|
108
|
+
packages_install,
|
|
109
|
+
packages_list,
|
|
110
|
+
packages_restore,
|
|
111
|
+
packages_snapshot,
|
|
112
|
+
packages_status,
|
|
113
|
+
packages_update,
|
|
114
|
+
)
|
|
115
|
+
from framework.project import project_root
|
|
116
|
+
from framework.quarto import quarto_generate_all, quarto_regenerate
|
|
117
|
+
from framework.scaffold import project_info, scaffold, status
|
|
118
|
+
from framework.scratch import scratch_capture, scratch_clean
|
|
119
|
+
from framework.security import AuditResult, git_security_audit
|
|
120
|
+
from framework.settings import settings, settings_read, settings_write
|
|
121
|
+
from framework.spec.check import spec_check
|
|
122
|
+
from framework.spec.merge import SpecError
|
|
123
|
+
from framework.spec.resolve import ResolvedSpec, spec_resolve
|
|
124
|
+
from framework.storage import (
|
|
125
|
+
publish,
|
|
126
|
+
publish_data,
|
|
127
|
+
publish_dir,
|
|
128
|
+
publish_list,
|
|
129
|
+
publish_notebook,
|
|
130
|
+
storage_test,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
__version__ = version("framework-py")
|
|
135
|
+
except PackageNotFoundError: # pragma: no cover (running from a source tree)
|
|
136
|
+
__version__ = "0.0.0"
|
|
137
|
+
|
|
138
|
+
__all__ = [
|
|
139
|
+
"AuditResult",
|
|
140
|
+
"BootstrapResult",
|
|
141
|
+
"CacheWarning",
|
|
142
|
+
"CapturedOutput",
|
|
143
|
+
"CloudError",
|
|
144
|
+
"Connection",
|
|
145
|
+
"DataChangedWarning",
|
|
146
|
+
"DataInfo",
|
|
147
|
+
"DataNotFoundError",
|
|
148
|
+
"FrameworkError",
|
|
149
|
+
"FrameworkWarning",
|
|
150
|
+
"IntegrityError",
|
|
151
|
+
"PackagesStatus",
|
|
152
|
+
"ProjectNotFoundError",
|
|
153
|
+
"ResolvedSpec",
|
|
154
|
+
"SettingsError",
|
|
155
|
+
"SpecError",
|
|
156
|
+
"UnsupportedFormatError",
|
|
157
|
+
"__version__",
|
|
158
|
+
"ai_skills_update",
|
|
159
|
+
"bootstrap",
|
|
160
|
+
"cache",
|
|
161
|
+
"cache_flush",
|
|
162
|
+
"cache_forget",
|
|
163
|
+
"cache_get",
|
|
164
|
+
"cache_list",
|
|
165
|
+
"cache_remember",
|
|
166
|
+
"capture_output",
|
|
167
|
+
"cloud_login",
|
|
168
|
+
"cloud_logout",
|
|
169
|
+
"cloud_settings",
|
|
170
|
+
"cloud_status",
|
|
171
|
+
"cloud_sync",
|
|
172
|
+
"config_dir",
|
|
173
|
+
"config_sync",
|
|
174
|
+
"configure_global",
|
|
175
|
+
"connections_list",
|
|
176
|
+
"data_add",
|
|
177
|
+
"data_info",
|
|
178
|
+
"data_list",
|
|
179
|
+
"data_read",
|
|
180
|
+
"data_save",
|
|
181
|
+
"data_verify",
|
|
182
|
+
"db_connect",
|
|
183
|
+
"db_drivers_status",
|
|
184
|
+
"db_execute",
|
|
185
|
+
"db_list",
|
|
186
|
+
"db_query",
|
|
187
|
+
"db_transaction",
|
|
188
|
+
"framework_template_path",
|
|
189
|
+
"git_hooks_disable",
|
|
190
|
+
"git_hooks_enable",
|
|
191
|
+
"git_hooks_install",
|
|
192
|
+
"git_hooks_list",
|
|
193
|
+
"git_hooks_uninstall",
|
|
194
|
+
"git_security_audit",
|
|
195
|
+
"global_settings",
|
|
196
|
+
"ledger_list",
|
|
197
|
+
"ledger_push",
|
|
198
|
+
"load_settings_catalog",
|
|
199
|
+
"make_notebook",
|
|
200
|
+
"make_presentation",
|
|
201
|
+
"make_qmd",
|
|
202
|
+
"make_revealjs",
|
|
203
|
+
"make_script",
|
|
204
|
+
"new",
|
|
205
|
+
"now",
|
|
206
|
+
"package_add",
|
|
207
|
+
"packages_install",
|
|
208
|
+
"packages_list",
|
|
209
|
+
"packages_restore",
|
|
210
|
+
"packages_snapshot",
|
|
211
|
+
"packages_status",
|
|
212
|
+
"packages_update",
|
|
213
|
+
"project_add_directory",
|
|
214
|
+
"project_create",
|
|
215
|
+
"project_create_from_layers",
|
|
216
|
+
"project_info",
|
|
217
|
+
"project_list",
|
|
218
|
+
"project_register",
|
|
219
|
+
"project_root",
|
|
220
|
+
"project_unregister",
|
|
221
|
+
"publish",
|
|
222
|
+
"publish_data",
|
|
223
|
+
"publish_dir",
|
|
224
|
+
"publish_list",
|
|
225
|
+
"publish_notebook",
|
|
226
|
+
"quarto_generate_all",
|
|
227
|
+
"quarto_regenerate",
|
|
228
|
+
"read_framework_template",
|
|
229
|
+
"reset_framework_template",
|
|
230
|
+
"result_list",
|
|
231
|
+
"save_figure",
|
|
232
|
+
"save_model",
|
|
233
|
+
"save_notebook",
|
|
234
|
+
"save_report",
|
|
235
|
+
"save_table",
|
|
236
|
+
"scaffold",
|
|
237
|
+
"scratch_capture",
|
|
238
|
+
"scratch_clean",
|
|
239
|
+
"settings",
|
|
240
|
+
"settings_read",
|
|
241
|
+
"settings_write",
|
|
242
|
+
"spec_check",
|
|
243
|
+
"spec_resolve",
|
|
244
|
+
"status",
|
|
245
|
+
"storage_test",
|
|
246
|
+
"stubs_list",
|
|
247
|
+
"stubs_path",
|
|
248
|
+
"stubs_publish",
|
|
249
|
+
"write_framework_template",
|
|
250
|
+
]
|
framework/__main__.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""Command-line entry points: ``python -m framework``.
|
|
2
|
+
|
|
3
|
+
python -m framework create --from-layers FILE --path DIR [--interactive]
|
|
4
|
+
python -m framework create --name NAME --path DIR [--type TYPE] [--interactive]
|
|
5
|
+
python -m framework bootstrap [--path DIR] [--interactive] [--no-packages]
|
|
6
|
+
python -m framework hook pre-commit
|
|
7
|
+
|
|
8
|
+
Exit codes: 0 on success, 1 on failure (the message is on stderr), and 2 for
|
|
9
|
+
a usage error.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import sys
|
|
16
|
+
from collections.abc import Sequence
|
|
17
|
+
|
|
18
|
+
from framework.errors import FrameworkError
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _parser() -> argparse.ArgumentParser:
|
|
22
|
+
parser = argparse.ArgumentParser(prog="python -m framework", description="Framework for Python")
|
|
23
|
+
commands = parser.add_subparsers(dest="command", required=True)
|
|
24
|
+
|
|
25
|
+
create = commands.add_parser("create", help="create a Python project")
|
|
26
|
+
source = create.add_mutually_exclusive_group(required=True)
|
|
27
|
+
source.add_argument(
|
|
28
|
+
"--from-layers", metavar="FILE", help="a layers file (framework.pub format)"
|
|
29
|
+
)
|
|
30
|
+
source.add_argument("--name", help="project name; your defaults apply, as with framework.new()")
|
|
31
|
+
create.add_argument("--path", required=True, help="the project folder to create")
|
|
32
|
+
create.add_argument(
|
|
33
|
+
"--type",
|
|
34
|
+
choices=["project", "project_sensitive", "course", "presentation", "bare"],
|
|
35
|
+
help="project type, with --name (default: bare, or asked with --interactive)",
|
|
36
|
+
)
|
|
37
|
+
create.add_argument(
|
|
38
|
+
"--interactive",
|
|
39
|
+
action="store_true",
|
|
40
|
+
help="prompt for missing answers, initialize git, and register the project",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
bootstrap = commands.add_parser("bootstrap", help="prepare a cloned project")
|
|
44
|
+
bootstrap.add_argument("--path", default=".", help="the project folder (default: .)")
|
|
45
|
+
bootstrap.add_argument("--interactive", action="store_true", help="ask for empty .env values")
|
|
46
|
+
bootstrap.add_argument(
|
|
47
|
+
"--no-packages", action="store_true", help="skip installing packages with uv"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
hook = commands.add_parser("hook", help="run a git hook's checks (called by the hook)")
|
|
51
|
+
hook.add_argument("name", choices=["pre-commit"])
|
|
52
|
+
return parser
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def main(argv: Sequence[str] | None = None) -> int:
|
|
56
|
+
parser = _parser()
|
|
57
|
+
args = parser.parse_args(argv)
|
|
58
|
+
if args.command == "hook":
|
|
59
|
+
from framework.hooks import hook_run
|
|
60
|
+
|
|
61
|
+
return hook_run(args.name)
|
|
62
|
+
if args.command == "create" and args.from_layers and args.type:
|
|
63
|
+
parser.error("--type can only be used with --name")
|
|
64
|
+
try:
|
|
65
|
+
if args.command == "bootstrap":
|
|
66
|
+
from framework.bootstrap import bootstrap
|
|
67
|
+
|
|
68
|
+
path = bootstrap(
|
|
69
|
+
args.path, interactive=args.interactive, packages=not args.no_packages
|
|
70
|
+
).root
|
|
71
|
+
elif args.from_layers:
|
|
72
|
+
from framework.create import project_create_from_layers
|
|
73
|
+
|
|
74
|
+
path = project_create_from_layers(
|
|
75
|
+
args.from_layers, args.path, interactive=args.interactive
|
|
76
|
+
)
|
|
77
|
+
else:
|
|
78
|
+
from framework.create import new
|
|
79
|
+
|
|
80
|
+
path = new(args.name, args.path, args.type, interactive=args.interactive)
|
|
81
|
+
except FrameworkError as error:
|
|
82
|
+
print(f"Error: {error}", file=sys.stderr)
|
|
83
|
+
return 1
|
|
84
|
+
print(path)
|
|
85
|
+
return 0
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
if __name__ == "__main__":
|
|
89
|
+
sys.exit(main())
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Framework pre-commit hook (shared by R, Python, and fw)
|
|
3
|
+
# Managed by Framework. Configure it with git_hooks_*() in R or Python.
|
|
4
|
+
#
|
|
5
|
+
# The checks themselves live in the language packages, which read
|
|
6
|
+
# git.hooks in settings.yml to decide what to run. This script only finds a
|
|
7
|
+
# runtime. A project with no usable runtime fails the commit, because the
|
|
8
|
+
# hook guards against committing restricted data. Bypass with
|
|
9
|
+
# `git commit --no-verify` only when you know the commit is safe.
|
|
10
|
+
|
|
11
|
+
set -u
|
|
12
|
+
|
|
13
|
+
cd "$(git rev-parse --show-toplevel)" || exit 1
|
|
14
|
+
|
|
15
|
+
run_r() {
|
|
16
|
+
command -v Rscript >/dev/null 2>&1 || return 127
|
|
17
|
+
Rscript -e 'quit(status = framework:::.hook_run("pre-commit"))'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
run_python() {
|
|
21
|
+
if [ -x .venv/bin/python ]; then
|
|
22
|
+
.venv/bin/python -m framework hook pre-commit
|
|
23
|
+
elif [ -x .venv/Scripts/python.exe ]; then
|
|
24
|
+
.venv/Scripts/python.exe -m framework hook pre-commit
|
|
25
|
+
elif [ -f uv.lock ] && command -v uv >/dev/null 2>&1; then
|
|
26
|
+
uv run --frozen python -m framework hook pre-commit
|
|
27
|
+
elif command -v python3 >/dev/null 2>&1; then
|
|
28
|
+
python3 -m framework hook pre-commit
|
|
29
|
+
else
|
|
30
|
+
return 127
|
|
31
|
+
fi
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
has_rproj() {
|
|
35
|
+
for f in ./*.Rproj; do
|
|
36
|
+
[ -e "$f" ] && return 0
|
|
37
|
+
done
|
|
38
|
+
return 1
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# fw's detection plus *.Rproj, which every R-built project has even without
|
|
42
|
+
# renv. R markers are checked first; a project with both runs the first
|
|
43
|
+
# runtime that is installed.
|
|
44
|
+
status=127
|
|
45
|
+
if [ -f renv.lock ] || [ -f .Rprofile ] || has_rproj; then
|
|
46
|
+
run_r
|
|
47
|
+
status=$?
|
|
48
|
+
fi
|
|
49
|
+
if [ "$status" -eq 127 ] && { [ -f pyproject.toml ] || [ -f uv.lock ] || [ -d .venv ]; }; then
|
|
50
|
+
run_python
|
|
51
|
+
status=$?
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
if [ "$status" -eq 127 ]; then
|
|
55
|
+
echo "Framework hook: no R or Python runtime with framework installed was found." >&2
|
|
56
|
+
echo "Install one, or run 'git commit --no-verify' if you are sure this commit is safe." >&2
|
|
57
|
+
exit 1
|
|
58
|
+
fi
|
|
59
|
+
exit "$status"
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
CREATE TABLE results (
|
|
2
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
3
|
+
name TEXT UNIQUE,
|
|
4
|
+
type TEXT,
|
|
5
|
+
public BOOLEAN,
|
|
6
|
+
blind BOOLEAN,
|
|
7
|
+
comment TEXT,
|
|
8
|
+
hash TEXT,
|
|
9
|
+
last_read_at DATETIME,
|
|
10
|
+
created_at DATETIME,
|
|
11
|
+
updated_at DATETIME,
|
|
12
|
+
deleted_at DATETIME
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
CREATE TABLE data (
|
|
16
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
17
|
+
name TEXT UNIQUE,
|
|
18
|
+
path TEXT,
|
|
19
|
+
type TEXT,
|
|
20
|
+
delimiter TEXT,
|
|
21
|
+
locked BOOLEAN,
|
|
22
|
+
encrypted BOOLEAN,
|
|
23
|
+
hash TEXT,
|
|
24
|
+
last_read_at DATETIME,
|
|
25
|
+
created_at DATETIME,
|
|
26
|
+
updated_at DATETIME,
|
|
27
|
+
deleted_at DATETIME
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
CREATE TABLE cache (
|
|
31
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
32
|
+
name TEXT UNIQUE,
|
|
33
|
+
file_path TEXT,
|
|
34
|
+
hash TEXT,
|
|
35
|
+
expire_at DATETIME,
|
|
36
|
+
last_read_at DATETIME,
|
|
37
|
+
created_at DATETIME,
|
|
38
|
+
updated_at DATETIME,
|
|
39
|
+
deleted_at DATETIME
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
CREATE TABLE connections (
|
|
43
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
44
|
+
name TEXT UNIQUE,
|
|
45
|
+
driver TEXT,
|
|
46
|
+
host TEXT,
|
|
47
|
+
port INTEGER,
|
|
48
|
+
database TEXT,
|
|
49
|
+
schema TEXT,
|
|
50
|
+
user TEXT,
|
|
51
|
+
password TEXT,
|
|
52
|
+
last_used_at DATETIME,
|
|
53
|
+
created_at DATETIME,
|
|
54
|
+
updated_at DATETIME,
|
|
55
|
+
deleted_at DATETIME
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
CREATE TABLE meta (
|
|
59
|
+
key TEXT PRIMARY KEY,
|
|
60
|
+
value TEXT,
|
|
61
|
+
created_at DATETIME,
|
|
62
|
+
updated_at DATETIME
|
|
63
|
+
);
|