caspian-db 0.0.1__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.
- caspian_db-0.0.1/AGENTS.md +22 -0
- caspian_db-0.0.1/LICENSE +9 -0
- caspian_db-0.0.1/MANIFEST.in +2 -0
- caspian_db-0.0.1/PKG-INFO +162 -0
- caspian_db-0.0.1/PORTING.md +25 -0
- caspian_db-0.0.1/README.md +130 -0
- caspian_db-0.0.1/pyproject.toml +50 -0
- caspian_db-0.0.1/setup.cfg +4 -0
- caspian_db-0.0.1/src/caspian_db/__init__.py +3 -0
- caspian_db-0.0.1/src/caspian_db/__main__.py +3 -0
- caspian_db-0.0.1/src/caspian_db/cli.py +95 -0
- caspian_db-0.0.1/src/caspian_db/emitter.py +513 -0
- caspian_db-0.0.1/src/caspian_db/generate.py +106 -0
- caspian_db-0.0.1/src/caspian_db/migrations.py +188 -0
- caspian_db-0.0.1/src/caspian_db/psl.py +281 -0
- caspian_db-0.0.1/src/caspian_db/schema.py +110 -0
- caspian_db-0.0.1/src/caspian_db/template_support.py +136 -0
- caspian_db-0.0.1/src/caspian_db/templates.py +7797 -0
- caspian_db-0.0.1/src/caspian_db.egg-info/PKG-INFO +162 -0
- caspian_db-0.0.1/src/caspian_db.egg-info/SOURCES.txt +28 -0
- caspian_db-0.0.1/src/caspian_db.egg-info/dependency_links.txt +1 -0
- caspian_db-0.0.1/src/caspian_db.egg-info/entry_points.txt +2 -0
- caspian_db-0.0.1/src/caspian_db.egg-info/requires.txt +14 -0
- caspian_db-0.0.1/src/caspian_db.egg-info/top_level.txt +1 -0
- caspian_db-0.0.1/tests/fixtures/app.json +283 -0
- caspian_db-0.0.1/tests/fixtures/features-parity.json +17 -0
- caspian_db-0.0.1/tests/fixtures/features.json +420 -0
- caspian_db-0.0.1/tests/fixtures/legacy-parity.json +17 -0
- caspian_db-0.0.1/tests/test_generate.py +189 -0
- caspian_db-0.0.1/tests/test_native_workflow.py +196 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Caspian DB agent instructions
|
|
2
|
+
|
|
3
|
+
Read README.md and PORTING.md before editing. This installable package is separate
|
|
4
|
+
from the sibling app's installed Caspian runtime; never vendor or edit that runtime
|
|
5
|
+
as part of database-tooling migration.
|
|
6
|
+
|
|
7
|
+
Edit src/caspian_db, not a consuming app's generated client. Preserve imports,
|
|
8
|
+
delegates, typed inputs, and errors unless a deliberate API migration is requested.
|
|
9
|
+
Use native --schema generation; --metadata is legacy input compatibility only.
|
|
10
|
+
|
|
11
|
+
Generation/validation must never connect to a database, invoke Node/subprocesses,
|
|
12
|
+
launch watchers, or run implicit migrations/seeds. migrate create only creates a
|
|
13
|
+
reviewable SQL template. Deploy and seed are intentional data operations within
|
|
14
|
+
the user's authorized scope. Preserve migration files, checksums, and ledger data;
|
|
15
|
+
do not auto-baseline, reset, resolve failures, or replay existing migrations.
|
|
16
|
+
|
|
17
|
+
Run uv run python -m pytest tests -q, uv run ruff check src tests, and uv build.
|
|
18
|
+
Database tests use disposable SQLite databases or session-local PostgreSQL temporary
|
|
19
|
+
tables with a verified temporary search_path. Never use app tables as test fixtures.
|
|
20
|
+
|
|
21
|
+
Document unsupported schema grammar and migration/provider features candidly.
|
|
22
|
+
MySQL client generation does not imply MySQL migration deployment support.
|
caspian_db-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 The Steel Ninja Code - Jefferson Abraham Omier
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: caspian-db
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Caspian's native Python client generator for Prisma schema metadata
|
|
5
|
+
Author: Jefferson Abraham Omier
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Keywords: prisma,orm,database,codegen,migrations,caspian
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
+
Classifier: Topic :: Database
|
|
15
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
16
|
+
Classifier: Framework :: AsyncIO
|
|
17
|
+
Requires-Python: >=3.14
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: python-dotenv>=1.2.3
|
|
21
|
+
Requires-Dist: sqlparse>=0.6.0
|
|
22
|
+
Provides-Extra: postgresql
|
|
23
|
+
Requires-Dist: asyncpg>=0.31; extra == "postgresql"
|
|
24
|
+
Requires-Dist: python-dotenv>=1; extra == "postgresql"
|
|
25
|
+
Provides-Extra: mysql
|
|
26
|
+
Requires-Dist: aiomysql>=0.3; extra == "mysql"
|
|
27
|
+
Requires-Dist: python-dotenv>=1; extra == "mysql"
|
|
28
|
+
Provides-Extra: sqlite
|
|
29
|
+
Requires-Dist: aiosqlite>=0.22; extra == "sqlite"
|
|
30
|
+
Requires-Dist: python-dotenv>=1; extra == "sqlite"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# Caspian DB
|
|
34
|
+
|
|
35
|
+
Native Python tooling for Caspian's Prisma schema, generated client, reviewed SQL
|
|
36
|
+
migrations, and app-owned Python seed. Distribution: `caspian-db`; import:
|
|
37
|
+
`caspian_db`; command: `caspian-db`. Python 3.14 or newer. No Node/npm subprocess.
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
From PyPI, with the driver extra for your provider (`postgresql`, `mysql`, or
|
|
42
|
+
`sqlite`):
|
|
43
|
+
|
|
44
|
+
```powershell
|
|
45
|
+
uv add "caspian-db[postgresql]"
|
|
46
|
+
# or: pip install "caspian-db[postgresql]"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Then, from your Caspian application:
|
|
50
|
+
|
|
51
|
+
```powershell
|
|
52
|
+
uv run caspian-db validate
|
|
53
|
+
uv run caspian-db generate
|
|
54
|
+
uv run caspian-db generate --check
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
By default the schema is read from `prisma/` and the client is generated into
|
|
58
|
+
`src/lib/prisma`. Use `--schema` and `--output` to choose other locations:
|
|
59
|
+
|
|
60
|
+
```powershell
|
|
61
|
+
uv run caspian-db generate --schema path/to/schema.prisma --output path/to/client
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`uv run python -m caspian_db` provides the same interface. Commands use the current
|
|
65
|
+
project directory; pass explicit paths when running elsewhere. `uv build` produces
|
|
66
|
+
an installable wheel and source distribution.
|
|
67
|
+
|
|
68
|
+
## Schema and client
|
|
69
|
+
|
|
70
|
+
`--schema` accepts a `.prisma` file or a directory containing multiple `.prisma`
|
|
71
|
+
files. Default: `prisma`. Generation reads source directly; no generated metadata
|
|
72
|
+
manifest is needed. `--metadata` remains an explicit legacy compatibility input.
|
|
73
|
+
|
|
74
|
+
Supported client providers: PostgreSQL, MySQL, and SQLite. The strict schema reader
|
|
75
|
+
supports models/enums, mappings, optional/list fields, defaults, updatedAt, named
|
|
76
|
+
relations and inverse relations, compound primary/unique keys, and native-type
|
|
77
|
+
annotations. It rejects unsupported declarations and attributes instead of
|
|
78
|
+
silently dropping models. Supported scalar types: String, Int, Boolean, DateTime,
|
|
79
|
+
Float, BigInt, Decimal, Json. Multi-schema, views, composite types, ignore/fulltext,
|
|
80
|
+
expression/sorted compound keys, and Bytes/Unsupported types are not implemented.
|
|
81
|
+
Mapped names currently accept letters/digits/underscores/spaces/periods/hyphens.
|
|
82
|
+
This is a Caspian schema reader, not the complete Prisma language validator.
|
|
83
|
+
|
|
84
|
+
Generated files remain `models.py`, `db.py`, and `__init__.py`. App imports such as
|
|
85
|
+
`from src.lib.prisma import prisma` and existing delegate/query APIs are preserved.
|
|
86
|
+
`validate` checks schema and generated syntax; `generate --check` checks the client
|
|
87
|
+
against source. Neither compares a live database's structure to the schema.
|
|
88
|
+
Native type, index, and foreign-key action annotations describe database structure;
|
|
89
|
+
the client generator does not apply them. Express those changes in migration SQL.
|
|
90
|
+
|
|
91
|
+
All outputs compile before publication. A process lock serializes writers; staged
|
|
92
|
+
per-file replacements roll back on write errors. Authored files and file symlinks
|
|
93
|
+
are refused. Unchanged output keeps timestamps. Publication is not a crash-atomic
|
|
94
|
+
directory swap: stop Python before generation and regenerate after an interrupted
|
|
95
|
+
publication. No watchers, automatic reloads, seeds, or migrations run implicitly.
|
|
96
|
+
|
|
97
|
+
## Reviewed SQL migrations
|
|
98
|
+
|
|
99
|
+
```powershell
|
|
100
|
+
uv run caspian-db migrate create --name add_profile
|
|
101
|
+
# Edit and review the created prisma/migrations/<timestamp>_add_profile/migration.sql.
|
|
102
|
+
uv run caspian-db migrate status
|
|
103
|
+
uv run caspian-db migrate deploy
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`create` writes a template only. It does not derive a schema diff, connect to the
|
|
107
|
+
DB, or apply SQL. `status` uses a read-only transaction and reports pending SQL.
|
|
108
|
+
`deploy` is an explicit database write operation. Review its target and SQL first.
|
|
109
|
+
Commands accept `--schema` and `--migrations`. DATABASE_URL loads from the current
|
|
110
|
+
project's `.env` unless already set in the environment; credentials are not printed.
|
|
111
|
+
|
|
112
|
+
Deployment supports PostgreSQL and SQLite. Provider mismatch, changed/missing
|
|
113
|
+
applied migrations, non-prefix history, and unresolved failures stop deployment.
|
|
114
|
+
Existing `_prisma_migrations` records and original SQL file checksums are reused;
|
|
115
|
+
there is no automatic baseline or replay. Local `migration_lock.toml` is preserved.
|
|
116
|
+
PostgreSQL uses a transaction advisory lock; SQLite uses BEGIN IMMEDIATE. Pending
|
|
117
|
+
SQL and ledger entries commit together as one batch; a failure rolls back the batch.
|
|
118
|
+
Transaction controls and nontransactional operations such as CONCURRENTLY are
|
|
119
|
+
refused. SQL is trusted, reviewed project source, not uploaded/untrusted input.
|
|
120
|
+
|
|
121
|
+
Failed existing Prisma migrations need deliberate recovery; this package does not
|
|
122
|
+
provide an automatic resolve/reset command. Recovery uses a reviewed follow-up
|
|
123
|
+
migration or explicit DBA intervention. It does not generate down migrations,
|
|
124
|
+
perform schema drift detection, db push/introspection, or provide Prisma Studio.
|
|
125
|
+
MySQL client generation remains supported; MySQL migration deployment is not
|
|
126
|
+
implemented because its DDL transaction semantics need a separate runner.
|
|
127
|
+
|
|
128
|
+
## Python seed
|
|
129
|
+
|
|
130
|
+
```powershell
|
|
131
|
+
uv run caspian-db seed
|
|
132
|
+
uv run caspian-db seed --demo-user
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
`seed` loads `prisma/seed.py` (override with `--file`) and awaits its `run(demo_user=...)`
|
|
136
|
+
function. The consuming app owns the seed policy. Never execute seeds implicitly.
|
|
137
|
+
The migrated Caspian app seed creates missing Admin/User roles in a transaction,
|
|
138
|
+
keeps existing records unchanged, and never deletes users or resets counters.
|
|
139
|
+
The optional demo user requires CASPIAN_SEED_DEMO_PASSWORD, hashes it, and does not
|
|
140
|
+
replace an existing user's credentials. No built-in destructive reset is supplied.
|
|
141
|
+
|
|
142
|
+
## Dependencies and verification
|
|
143
|
+
|
|
144
|
+
Generation/schema reading uses the standard library. Migration SQL classification
|
|
145
|
+
uses sqlparse; environment loading uses python-dotenv. Generated clients need the
|
|
146
|
+
provider driver; extras: `caspian-db[postgresql]`, `[mysql]`, `[sqlite]`. The app
|
|
147
|
+
already installs its drivers. For exact ID default formats, install `cuid2`,
|
|
148
|
+
`nanoid`, or `python-ulid`; the preserved client otherwise falls back to UUID.
|
|
149
|
+
|
|
150
|
+
```powershell
|
|
151
|
+
uv sync --group dev
|
|
152
|
+
uv run python -m pytest tests -q
|
|
153
|
+
uv run ruff check src tests
|
|
154
|
+
uv build
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Tests include independent legacy-output AST parity for three client providers,
|
|
158
|
+
native multi-file parsing, no-Node execution, preservation on failure, concurrency,
|
|
159
|
+
and SQLite migration history/rollback plus generated-client CRUD. The consuming
|
|
160
|
+
app has an opt-in PostgreSQL test using only session-local temporary tables to
|
|
161
|
+
verify deployment, history, rollback, additive seeding, and client operations.
|
|
162
|
+
MySQL execution is still unverified. Read `PORTING.md` and `AGENTS.md` before edits.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Generator and database-tooling migration
|
|
2
|
+
|
|
3
|
+
Original source: prisma-client-python-dev/src/generate-python-orm.ts, MIT licensed.
|
|
4
|
+
LICENSE preserves the upstream attribution. The pure emitter was ported to Python;
|
|
5
|
+
emitter.py contains generation logic, templates.py readable source fragments, and
|
|
6
|
+
template_support.py collection/string helpers preserving old output semantics.
|
|
7
|
+
One-time TypeScript AST extraction is not a build/runtime dependency. Fixture
|
|
8
|
+
hashes independently captured the old renderer without running its prebuild.
|
|
9
|
+
|
|
10
|
+
schema.py normalizes metadata. psl.py reads supported Prisma schema declarations
|
|
11
|
+
directly, validates named/implicit inverse relations, and rejects unsupported input.
|
|
12
|
+
generate.py validates all outputs and controls locking/publication. migrations.py
|
|
13
|
+
runs reviewed transactional SQL using existing Prisma history. cli.py exposes
|
|
14
|
+
separate generation, validation, migration, and Python-seed commands.
|
|
15
|
+
|
|
16
|
+
The current PostgreSQL application's full authoring/generation/migration/seed path
|
|
17
|
+
requires no Prisma Node CLI, TypeScript config, Node client, or metadata bridge.
|
|
18
|
+
The generated Python API stays compatible. SQLite deployment is also covered.
|
|
19
|
+
|
|
20
|
+
This package is not a reimplementation of all official Prisma CLI features:
|
|
21
|
+
automatic schema-to-SQL diffing, introspection/db push, Studio, automatic failure
|
|
22
|
+
resolution/down migrations, full Prisma grammar, and MySQL DDL deployment are
|
|
23
|
+
not supplied. Migration SQL is authored/reviewed explicitly. MySQL runtime tests
|
|
24
|
+
and gradual refactoring of numbered template fragments remain improvement work.
|
|
25
|
+
The legacy client's optional ID libraries still fall back to UUID when absent.
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Caspian DB
|
|
2
|
+
|
|
3
|
+
Native Python tooling for Caspian's Prisma schema, generated client, reviewed SQL
|
|
4
|
+
migrations, and app-owned Python seed. Distribution: `caspian-db`; import:
|
|
5
|
+
`caspian_db`; command: `caspian-db`. Python 3.14 or newer. No Node/npm subprocess.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
From PyPI, with the driver extra for your provider (`postgresql`, `mysql`, or
|
|
10
|
+
`sqlite`):
|
|
11
|
+
|
|
12
|
+
```powershell
|
|
13
|
+
uv add "caspian-db[postgresql]"
|
|
14
|
+
# or: pip install "caspian-db[postgresql]"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Then, from your Caspian application:
|
|
18
|
+
|
|
19
|
+
```powershell
|
|
20
|
+
uv run caspian-db validate
|
|
21
|
+
uv run caspian-db generate
|
|
22
|
+
uv run caspian-db generate --check
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
By default the schema is read from `prisma/` and the client is generated into
|
|
26
|
+
`src/lib/prisma`. Use `--schema` and `--output` to choose other locations:
|
|
27
|
+
|
|
28
|
+
```powershell
|
|
29
|
+
uv run caspian-db generate --schema path/to/schema.prisma --output path/to/client
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`uv run python -m caspian_db` provides the same interface. Commands use the current
|
|
33
|
+
project directory; pass explicit paths when running elsewhere. `uv build` produces
|
|
34
|
+
an installable wheel and source distribution.
|
|
35
|
+
|
|
36
|
+
## Schema and client
|
|
37
|
+
|
|
38
|
+
`--schema` accepts a `.prisma` file or a directory containing multiple `.prisma`
|
|
39
|
+
files. Default: `prisma`. Generation reads source directly; no generated metadata
|
|
40
|
+
manifest is needed. `--metadata` remains an explicit legacy compatibility input.
|
|
41
|
+
|
|
42
|
+
Supported client providers: PostgreSQL, MySQL, and SQLite. The strict schema reader
|
|
43
|
+
supports models/enums, mappings, optional/list fields, defaults, updatedAt, named
|
|
44
|
+
relations and inverse relations, compound primary/unique keys, and native-type
|
|
45
|
+
annotations. It rejects unsupported declarations and attributes instead of
|
|
46
|
+
silently dropping models. Supported scalar types: String, Int, Boolean, DateTime,
|
|
47
|
+
Float, BigInt, Decimal, Json. Multi-schema, views, composite types, ignore/fulltext,
|
|
48
|
+
expression/sorted compound keys, and Bytes/Unsupported types are not implemented.
|
|
49
|
+
Mapped names currently accept letters/digits/underscores/spaces/periods/hyphens.
|
|
50
|
+
This is a Caspian schema reader, not the complete Prisma language validator.
|
|
51
|
+
|
|
52
|
+
Generated files remain `models.py`, `db.py`, and `__init__.py`. App imports such as
|
|
53
|
+
`from src.lib.prisma import prisma` and existing delegate/query APIs are preserved.
|
|
54
|
+
`validate` checks schema and generated syntax; `generate --check` checks the client
|
|
55
|
+
against source. Neither compares a live database's structure to the schema.
|
|
56
|
+
Native type, index, and foreign-key action annotations describe database structure;
|
|
57
|
+
the client generator does not apply them. Express those changes in migration SQL.
|
|
58
|
+
|
|
59
|
+
All outputs compile before publication. A process lock serializes writers; staged
|
|
60
|
+
per-file replacements roll back on write errors. Authored files and file symlinks
|
|
61
|
+
are refused. Unchanged output keeps timestamps. Publication is not a crash-atomic
|
|
62
|
+
directory swap: stop Python before generation and regenerate after an interrupted
|
|
63
|
+
publication. No watchers, automatic reloads, seeds, or migrations run implicitly.
|
|
64
|
+
|
|
65
|
+
## Reviewed SQL migrations
|
|
66
|
+
|
|
67
|
+
```powershell
|
|
68
|
+
uv run caspian-db migrate create --name add_profile
|
|
69
|
+
# Edit and review the created prisma/migrations/<timestamp>_add_profile/migration.sql.
|
|
70
|
+
uv run caspian-db migrate status
|
|
71
|
+
uv run caspian-db migrate deploy
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`create` writes a template only. It does not derive a schema diff, connect to the
|
|
75
|
+
DB, or apply SQL. `status` uses a read-only transaction and reports pending SQL.
|
|
76
|
+
`deploy` is an explicit database write operation. Review its target and SQL first.
|
|
77
|
+
Commands accept `--schema` and `--migrations`. DATABASE_URL loads from the current
|
|
78
|
+
project's `.env` unless already set in the environment; credentials are not printed.
|
|
79
|
+
|
|
80
|
+
Deployment supports PostgreSQL and SQLite. Provider mismatch, changed/missing
|
|
81
|
+
applied migrations, non-prefix history, and unresolved failures stop deployment.
|
|
82
|
+
Existing `_prisma_migrations` records and original SQL file checksums are reused;
|
|
83
|
+
there is no automatic baseline or replay. Local `migration_lock.toml` is preserved.
|
|
84
|
+
PostgreSQL uses a transaction advisory lock; SQLite uses BEGIN IMMEDIATE. Pending
|
|
85
|
+
SQL and ledger entries commit together as one batch; a failure rolls back the batch.
|
|
86
|
+
Transaction controls and nontransactional operations such as CONCURRENTLY are
|
|
87
|
+
refused. SQL is trusted, reviewed project source, not uploaded/untrusted input.
|
|
88
|
+
|
|
89
|
+
Failed existing Prisma migrations need deliberate recovery; this package does not
|
|
90
|
+
provide an automatic resolve/reset command. Recovery uses a reviewed follow-up
|
|
91
|
+
migration or explicit DBA intervention. It does not generate down migrations,
|
|
92
|
+
perform schema drift detection, db push/introspection, or provide Prisma Studio.
|
|
93
|
+
MySQL client generation remains supported; MySQL migration deployment is not
|
|
94
|
+
implemented because its DDL transaction semantics need a separate runner.
|
|
95
|
+
|
|
96
|
+
## Python seed
|
|
97
|
+
|
|
98
|
+
```powershell
|
|
99
|
+
uv run caspian-db seed
|
|
100
|
+
uv run caspian-db seed --demo-user
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
`seed` loads `prisma/seed.py` (override with `--file`) and awaits its `run(demo_user=...)`
|
|
104
|
+
function. The consuming app owns the seed policy. Never execute seeds implicitly.
|
|
105
|
+
The migrated Caspian app seed creates missing Admin/User roles in a transaction,
|
|
106
|
+
keeps existing records unchanged, and never deletes users or resets counters.
|
|
107
|
+
The optional demo user requires CASPIAN_SEED_DEMO_PASSWORD, hashes it, and does not
|
|
108
|
+
replace an existing user's credentials. No built-in destructive reset is supplied.
|
|
109
|
+
|
|
110
|
+
## Dependencies and verification
|
|
111
|
+
|
|
112
|
+
Generation/schema reading uses the standard library. Migration SQL classification
|
|
113
|
+
uses sqlparse; environment loading uses python-dotenv. Generated clients need the
|
|
114
|
+
provider driver; extras: `caspian-db[postgresql]`, `[mysql]`, `[sqlite]`. The app
|
|
115
|
+
already installs its drivers. For exact ID default formats, install `cuid2`,
|
|
116
|
+
`nanoid`, or `python-ulid`; the preserved client otherwise falls back to UUID.
|
|
117
|
+
|
|
118
|
+
```powershell
|
|
119
|
+
uv sync --group dev
|
|
120
|
+
uv run python -m pytest tests -q
|
|
121
|
+
uv run ruff check src tests
|
|
122
|
+
uv build
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Tests include independent legacy-output AST parity for three client providers,
|
|
126
|
+
native multi-file parsing, no-Node execution, preservation on failure, concurrency,
|
|
127
|
+
and SQLite migration history/rollback plus generated-client CRUD. The consuming
|
|
128
|
+
app has an opt-in PostgreSQL test using only session-local temporary tables to
|
|
129
|
+
verify deployment, history, rollback, additive seeding, and client operations.
|
|
130
|
+
MySQL execution is still unverified. Read `PORTING.md` and `AGENTS.md` before edits.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "caspian-db"
|
|
7
|
+
version = "0.0.1"
|
|
8
|
+
description = "Caspian's native Python client generator for Prisma schema metadata"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.14"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [{ name = "Jefferson Abraham Omier" }]
|
|
14
|
+
keywords = ["prisma", "orm", "database", "codegen", "migrations", "caspian"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 3 - Alpha",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
21
|
+
"Programming Language :: Python :: 3.14",
|
|
22
|
+
"Topic :: Database",
|
|
23
|
+
"Topic :: Software Development :: Code Generators",
|
|
24
|
+
"Framework :: AsyncIO",
|
|
25
|
+
]
|
|
26
|
+
dependencies = [
|
|
27
|
+
"python-dotenv>=1.2.3",
|
|
28
|
+
"sqlparse>=0.6.0",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
postgresql = ["asyncpg>=0.31", "python-dotenv>=1"]
|
|
33
|
+
mysql = ["aiomysql>=0.3", "python-dotenv>=1"]
|
|
34
|
+
sqlite = ["aiosqlite>=0.22", "python-dotenv>=1"]
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
caspian-db = "caspian_db.cli:main"
|
|
38
|
+
|
|
39
|
+
[dependency-groups]
|
|
40
|
+
dev = ["pytest>=9", "ruff>=0.16", "aiosqlite>=0.22", "python-dotenv>=1"]
|
|
41
|
+
|
|
42
|
+
[tool.setuptools.packages.find]
|
|
43
|
+
where = ["src"]
|
|
44
|
+
|
|
45
|
+
[tool.ruff]
|
|
46
|
+
line-length = 100
|
|
47
|
+
|
|
48
|
+
[tool.ruff.lint]
|
|
49
|
+
select = ["E", "F", "W"]
|
|
50
|
+
ignore = ["E501"]
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Explicit code generation commands; no implicit schema/seed database changes."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import asyncio
|
|
5
|
+
import os
|
|
6
|
+
import runpy
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from .generate import generate, render
|
|
11
|
+
from .psl import read_schema
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def main(argv=None):
|
|
15
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
16
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
17
|
+
for name in ("generate", "validate"):
|
|
18
|
+
command = sub.add_parser(name)
|
|
19
|
+
inputs = command.add_mutually_exclusive_group()
|
|
20
|
+
inputs.add_argument("--metadata", type=Path, help="Legacy parsed metadata JSON")
|
|
21
|
+
inputs.add_argument(
|
|
22
|
+
"--schema",
|
|
23
|
+
type=Path,
|
|
24
|
+
default=Path("prisma"),
|
|
25
|
+
help=".prisma file or schema directory (default: prisma)",
|
|
26
|
+
)
|
|
27
|
+
if name == "generate":
|
|
28
|
+
command.add_argument(
|
|
29
|
+
"--output",
|
|
30
|
+
type=Path,
|
|
31
|
+
default=Path("src/lib/prisma"),
|
|
32
|
+
help="generated client directory (default: src/lib/prisma)",
|
|
33
|
+
)
|
|
34
|
+
command.add_argument(
|
|
35
|
+
"--check", action="store_true", help="check freshness without writes"
|
|
36
|
+
)
|
|
37
|
+
migrate = sub.add_parser("migrate", help="Reviewed SQL migration workflow")
|
|
38
|
+
actions = migrate.add_subparsers(dest="action", required=True)
|
|
39
|
+
for name in ("status", "deploy", "create"):
|
|
40
|
+
action = actions.add_parser(name)
|
|
41
|
+
action.add_argument("--schema", type=Path, default=Path("prisma"))
|
|
42
|
+
action.add_argument("--migrations", type=Path, default=Path("prisma/migrations"))
|
|
43
|
+
if name == "create":
|
|
44
|
+
action.add_argument("--name", required=True)
|
|
45
|
+
seed = sub.add_parser("seed", help="Execute the app's Python seed (writes data)")
|
|
46
|
+
seed.add_argument("--file", type=Path, default=Path("prisma/seed.py"))
|
|
47
|
+
seed.add_argument("--demo-user", action="store_true")
|
|
48
|
+
args = parser.parse_args(argv)
|
|
49
|
+
try:
|
|
50
|
+
if args.command == "validate":
|
|
51
|
+
render(args.metadata or args.schema)
|
|
52
|
+
print("Schema metadata and generated Python syntax are valid.")
|
|
53
|
+
elif args.command == "generate":
|
|
54
|
+
changed = generate(args.metadata or args.schema, args.output, check=args.check)
|
|
55
|
+
print("Generated " + ", ".join(changed) if changed else "Client is current.")
|
|
56
|
+
elif args.command == "migrate":
|
|
57
|
+
from .migrations import create_migration, postgres_run, sqlite_run
|
|
58
|
+
|
|
59
|
+
provider = read_schema(args.schema)["datasources"][0]["provider"]
|
|
60
|
+
if provider not in {"postgresql", "sqlite"}:
|
|
61
|
+
raise ValueError(
|
|
62
|
+
"Native migration deployment currently supports PostgreSQL and SQLite only"
|
|
63
|
+
)
|
|
64
|
+
if args.action == "create":
|
|
65
|
+
print(create_migration(args.migrations, args.name, provider))
|
|
66
|
+
else:
|
|
67
|
+
from dotenv import load_dotenv
|
|
68
|
+
|
|
69
|
+
load_dotenv(Path.cwd() / ".env")
|
|
70
|
+
url = os.environ.get("DATABASE_URL")
|
|
71
|
+
if not url:
|
|
72
|
+
raise ValueError("DATABASE_URL is required")
|
|
73
|
+
deploy = args.action == "deploy"
|
|
74
|
+
pending = (
|
|
75
|
+
asyncio.run(postgres_run(args.migrations, url, deploy))
|
|
76
|
+
if provider == "postgresql"
|
|
77
|
+
else sqlite_run(args.migrations, url, deploy)
|
|
78
|
+
)
|
|
79
|
+
print(("Applied: " if deploy else "Pending: ") + (", ".join(pending) or "none"))
|
|
80
|
+
else:
|
|
81
|
+
from dotenv import load_dotenv
|
|
82
|
+
|
|
83
|
+
load_dotenv(Path.cwd() / ".env")
|
|
84
|
+
sys.path.insert(0, str(Path.cwd()))
|
|
85
|
+
namespace = runpy.run_path(str(args.file))
|
|
86
|
+
asyncio.run(namespace["run"](demo_user=args.demo_user))
|
|
87
|
+
print("Seed completed.")
|
|
88
|
+
return 0
|
|
89
|
+
except Exception as exc:
|
|
90
|
+
print(f"caspian-db: {exc}", file=sys.stderr)
|
|
91
|
+
return 1
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__":
|
|
95
|
+
raise SystemExit(main())
|