ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/ns_dev/Python/NinoCode/Active_prgs/Gromulus/models.py
Revision: 991
Committed: Mon Mar 9 21:52:02 2026 UTC (2 weeks, 5 days ago) by nino.borges
Content type: text/x-python
File size: 4297 byte(s)
Log Message:
I meant to have this as the commit message for 1.5 but I had an issue wiht the message.  so I added some spaces to the files to force another commit.

Gromulus v1.5: user metadata save workflow, schema expansion, and UI refactor

- Added user-editable game metadata workflow with explicit Save button (no autosave).
- Added dirty-state tracking and Save/Discard/Cancel prompts when navigating away or closing with unsaved changes.
- Added DB schema support for new metadata fields:
  - favorite_game
  - release_date, release_date_scraped
  - game_genre, game_genre_scraped
  - cooperative, cooperative_scraped
  - max_players, max_players_scraped
- Wired UI to user-first metadata precedence with _scraped fallback for release date, genre, cooperative, max players, and description.
- Added release date display/storage conversion:
  - GUI display MM-DD-YYYY
  - DB storage YYYY-MM-DD
- Refactored main game info panel:
  - moved hash/file/No-Intro/TOSEC detail fields into Reports -> Game Properties modal
  - added compact TOSEC/NoIntro match indicators
  - added Favorite, Release Date, Genre, Cooperative, Max Players, Description, and User Notes controls
- Enhanced artwork previews from prior update:
  - larger preview boxes
  - aspect-ratio-preserving scaling
  - click-to-open full-size modal viewer
- Updated schema/documentation files to stay aligned:
  - models.py
  - Database Dictonary.md
  - canonical DB utility schema/migration logic


File Contents

# User Rev Content
1 nino.borges 988 """SQLAlchemy schema definitions for the current Gromulus SQLite database.
2 nino.borges 795
3 nino.borges 988 This module is intentionally written with SQLAlchemy Core ``Table`` objects
4     instead of ORM declarative classes so it can represent tables that do not
5     have primary keys (for example ``no_intro_main`` and ``tosec_main``).
6     """
7 nino.borges 795
8 nino.borges 988 from sqlalchemy import (
9     Column,
10     ForeignKey,
11     Index,
12     Integer,
13     MetaData,
14     Table,
15     Text,
16     UniqueConstraint,
17     )
18 nino.borges 795
19    
20 nino.borges 991
21 nino.borges 988 metadata = MetaData()
22 nino.borges 795
23    
24 nino.borges 988 main_app_system = Table(
25     "main_app_system",
26     metadata,
27     Column("id", Integer, primary_key=True, autoincrement=True, nullable=False),
28     Column("name", Text),
29     Column("short_name", Text),
30     Column("relative_file_path", Text),
31     )
32 nino.borges 795
33    
34 nino.borges 988 main_app = Table(
35     "main_app",
36     metadata,
37     Column("id", Integer, primary_key=True, autoincrement=True, nullable=False),
38     Column("game_name", Text),
39     Column("game_name_scraped", Text),
40     Column("container_file_name", Text),
41     Column("description", Text),
42     Column("description_scraped", Text),
43     Column("system_console", Integer),
44     Column("system_console_scraped", Text),
45     Column("path_to_screenshot_box", Text),
46     Column("path_to_screenshot_title", Text),
47     Column("path_to_screenshot_ingame", Text),
48     Column("path_to_video", Text),
49     Column("user_notes", Text),
50     Column("container_md5_hash", Text),
51     Column("version", Text),
52 nino.borges 990 Column("favorite_game", Integer),
53     Column("release_date", Text),
54     Column("release_date_scraped", Text),
55     Column("game_genre", Text),
56     Column("game_genre_scraped", Text),
57     Column("cooperative", Text),
58     Column("cooperative_scraped", Text),
59     Column("max_players", Text),
60     Column("max_players_scraped", Text),
61 nino.borges 988 )
62    
63    
64     main_app_file_hash = Table(
65     "main_app_file_hash",
66     metadata,
67     Column("id", Integer, primary_key=True, autoincrement=True, nullable=False),
68     Column("file_name", Text),
69     Column("file_md5_hash", Text),
70     Column("container_file_id", Integer, ForeignKey("main_app.id"), nullable=False),
71     )
72    
73    
74     no_intro_system = Table(
75     "no_intro_system",
76     metadata,
77     Column("id", Integer, primary_key=True, nullable=False),
78     Column("name", Text),
79     Column("description", Text),
80     Column("dat_version", Text),
81     )
82    
83    
84     no_intro_main = Table(
85     "no_intro_main",
86     metadata,
87     Column("game_name", Text),
88     Column("no_intro_id", Text),
89     Column("clone_of_id", Text),
90     Column("description", Text),
91     Column("rom_name", Text),
92     Column("crc", Text),
93     Column("md5", Text),
94     Column("sha1", Text),
95     Column("sha256", Text),
96     Column("status", Text),
97     Column("no_intro_system_id", Integer, ForeignKey("no_intro_system.id"), nullable=False),
98     Column("app_system_id", Integer),
99     )
100    
101    
102     tosec_main = Table(
103     "tosec_main",
104     metadata,
105     Column("game_name", Text),
106     Column("description", Text),
107     Column("rom_name", Text),
108     Column("crc", Text),
109     Column("md5", Text),
110     Column("sha1", Text),
111     Column("system_id", Integer, ForeignKey("no_intro_system.id"), nullable=False),
112     Column("app_system_id", Integer),
113     )
114    
115    
116     dat_import_history = Table(
117     "dat_import_history",
118     metadata,
119     Column("id", Integer, primary_key=True, autoincrement=True),
120     Column("app_system_id", Integer, ForeignKey("main_app_system.id"), nullable=False),
121     Column("source", Text, nullable=False),
122     Column("dat_name", Text),
123     Column("dat_description", Text),
124     Column("dat_version", Text),
125     Column("imported_at", Text, nullable=False),
126     Column("entry_count", Integer, nullable=False, default=0),
127     UniqueConstraint("app_system_id", "source", name="uq_dat_import_history_system_source"),
128     )
129    
130    
131     Index("idx_main_app_md5", main_app.c.container_md5_hash)
132     Index("idx_main_app_system", main_app.c.system_console)
133     Index("idx_no_intro_md5", no_intro_main.c.md5)
134     Index("idx_tosec_md5", tosec_main.c.md5)
135     Index("idx_no_intro_system_md5", no_intro_main.c.app_system_id, no_intro_main.c.md5)
136     Index("idx_tosec_system_md5", tosec_main.c.app_system_id, tosec_main.c.md5)
137     Index("idx_dat_import_system_source", dat_import_history.c.app_system_id, dat_import_history.c.source)
138    
139    
140     __all__ = [
141     "metadata",
142     "main_app_system",
143     "main_app",
144     "main_app_file_hash",
145     "no_intro_system",
146     "no_intro_main",
147     "tosec_main",
148     "dat_import_history",
149     ]