refactor: implement database-specific schema architecture with schema-as-query pattern
🏗️ **Major Database Schema Refactoring** **Problem Solved**: Eliminated model duplication and multiple sources of truth by: - Removed duplicate models (`internal/models/content.go`) - Replaced inlined schema strings with sqlc-generated setup functions - Implemented database-specific schemas with proper NOT NULL constraints **Key Improvements**: ✅ **Single Source of Truth**: Database schemas define all types, no manual sync needed ✅ **Clean Generated Types**: sqlc generates `string` and `int64` instead of `sql.NullString/sql.NullTime` ✅ **Schema-as-Query Pattern**: Setup functions generated by sqlc for type safety ✅ **Database-Specific Optimization**: SQLite INTEGER timestamps, PostgreSQL BIGINT timestamps ✅ **Cross-Database Compatibility**: Single codebase supports both SQLite and PostgreSQL **Architecture Changes**: - `db/sqlite/` - SQLite-specific schema and setup queries - `db/postgresql/` - PostgreSQL-specific schema and setup queries - `db/queries/` - Cross-database CRUD queries using `sqlc.arg()` syntax - `internal/db/database.go` - Database abstraction with runtime selection - `internal/api/models.go` - Clean API models for requests/responses **Version Control System**: Complete element-level history with user attribution and rollback **Verification**: ✅ Full API workflow tested (create → update → rollback → versions) **Production Ready**: Supports SQLite (development) → PostgreSQL (production) migration
This commit is contained in:
@@ -23,7 +23,7 @@ func main() {
|
||||
flag.Parse()
|
||||
|
||||
// Initialize database
|
||||
database, err := db.NewSQLiteDB(*dbPath)
|
||||
database, err := db.NewDatabase(*dbPath)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to initialize database: %v", err)
|
||||
}
|
||||
@@ -48,12 +48,17 @@ func main() {
|
||||
|
||||
// Content endpoints matching the expected API contract
|
||||
apiRouter.HandleFunc("/bulk", contentHandler.GetBulkContent).Methods("GET")
|
||||
apiRouter.HandleFunc("/{id}/versions", contentHandler.GetContentVersions).Methods("GET")
|
||||
apiRouter.HandleFunc("/{id}/rollback", contentHandler.RollbackContent).Methods("POST")
|
||||
apiRouter.HandleFunc("/{id}", contentHandler.GetContent).Methods("GET")
|
||||
apiRouter.HandleFunc("/{id}", contentHandler.UpdateContent).Methods("PUT")
|
||||
apiRouter.HandleFunc("/{id}", contentHandler.DeleteContent).Methods("DELETE")
|
||||
apiRouter.HandleFunc("", contentHandler.GetAllContent).Methods("GET")
|
||||
apiRouter.HandleFunc("", contentHandler.CreateContent).Methods("POST")
|
||||
|
||||
// Handle CORS preflight requests explicitly
|
||||
apiRouter.HandleFunc("/{id}/versions", api.CORSPreflightHandler).Methods("OPTIONS")
|
||||
apiRouter.HandleFunc("/{id}/rollback", api.CORSPreflightHandler).Methods("OPTIONS")
|
||||
apiRouter.HandleFunc("/{id}", api.CORSPreflightHandler).Methods("OPTIONS")
|
||||
apiRouter.HandleFunc("", api.CORSPreflightHandler).Methods("OPTIONS")
|
||||
apiRouter.HandleFunc("/bulk", api.CORSPreflightHandler).Methods("OPTIONS")
|
||||
@@ -68,8 +73,11 @@ func main() {
|
||||
fmt.Printf(" GET /api/content?site_id={site}\n")
|
||||
fmt.Printf(" GET /api/content/{id}?site_id={site}\n")
|
||||
fmt.Printf(" GET /api/content/bulk?site_id={site}&ids[]={id1}&ids[]={id2}\n")
|
||||
fmt.Printf(" GET /api/content/{id}/versions?site_id={site}\n")
|
||||
fmt.Printf(" POST /api/content\n")
|
||||
fmt.Printf(" PUT /api/content/{id}\n")
|
||||
fmt.Printf(" POST /api/content/{id}/rollback\n")
|
||||
fmt.Printf(" DELETE /api/content/{id}?site_id={site}\n")
|
||||
fmt.Printf("\n🔄 Press Ctrl+C to shutdown gracefully\n\n")
|
||||
|
||||
// Setup graceful shutdown
|
||||
|
||||
Reference in New Issue
Block a user