Seth commited on
Commit
70083b5
·
1 Parent(s): 144794a
Files changed (2) hide show
  1. backend/app/database.py +27 -47
  2. backend/requirements.txt +2 -1
backend/app/database.py CHANGED
@@ -1,8 +1,14 @@
1
  import os
2
- from sqlalchemy import create_engine, text, event
3
  from sqlalchemy.orm import sessionmaker, declarative_base
4
  from sqlalchemy.pool import NullPool
5
- from sqlalchemy.dialects import postgresql
 
 
 
 
 
 
6
 
7
  # Get database URL from environment variable
8
  # Default to SQLite for local development if not set
@@ -13,11 +19,13 @@ DATABASE_URL = os.getenv(
13
 
14
  # For CockroachDB, we need to handle SSL and connection pooling
15
  if DATABASE_URL.startswith("postgresql://") or DATABASE_URL.startswith("postgres://"):
 
 
 
16
  # CockroachDB connection - use NullPool to avoid connection issues
17
  # CockroachDB requires SSL, so we ensure sslmode is set
18
  # Use 'require' mode which uses SSL but doesn't require certificate file
19
  # For production with certificate, use 'verify-full' and provide sslrootcert
20
- import os
21
  cert_path = os.path.expanduser("~/.postgresql/root.crt")
22
 
23
  if "sslmode" not in DATABASE_URL:
@@ -30,32 +38,19 @@ if DATABASE_URL.startswith("postgresql://") or DATABASE_URL.startswith("postgres
30
  DATABASE_URL = DATABASE_URL.replace("sslmode=verify-full", "sslmode=require")
31
  print("⚠ Certificate file not found, using sslmode=require instead of verify-full")
32
 
33
- # Configure engine for CockroachDB compatibility
34
- # CockroachDB uses a different version string format, so we need to handle it
35
- connect_args = {}
36
- is_cockroach = "cockroachlabs" in DATABASE_URL.lower()
37
-
38
- if is_cockroach:
39
- # For CockroachDB, bypass version string parsing by setting version info
40
- # This prevents SQLAlchemy from trying to parse CockroachDB's version string
41
- connect_args["server_version"] = "12.0"
42
 
 
43
  engine = create_engine(
44
  DATABASE_URL,
45
  poolclass=NullPool, # CockroachDB works better with NullPool
46
  echo=False, # Set to True for SQL query debugging
47
- connect_args=connect_args
48
  )
49
-
50
- # Override version detection for CockroachDB at the dialect level
51
- if is_cockroach:
52
- @event.listens_for(engine, "connect", insert=True)
53
- def receive_connect(dbapi_conn, connection_record):
54
- # Set version info before SQLAlchemy tries to parse it
55
- # This happens at connection time
56
- if hasattr(connection_record, 'info'):
57
- connection_record.info["server_version_info"] = (12, 0)
58
- connection_record.info["server_version"] = "12.0"
59
  else:
60
  # SQLite for local development
61
  engine = create_engine(
@@ -80,36 +75,21 @@ def init_db():
80
  try:
81
  from app.models import User, Integration, Asset, Post, Campaign
82
 
83
- # Test connection and create tables
84
  # For CockroachDB, version parsing may fail but connection still works
85
- try:
86
- with engine.connect() as conn:
87
- conn.execute(text("SELECT 1"))
88
- conn.commit()
89
- except Exception as conn_error:
90
- error_str = str(conn_error)
91
- # If it's a version parsing error for CockroachDB, connection still works
92
- # We can proceed with table creation
93
- if "Could not determine version" not in error_str:
94
- # Real connection error, not just version parsing
95
- raise conn_error
96
-
97
- # Create tables - this should work even if version parsing failed
98
  Base.metadata.create_all(bind=engine)
 
99
  return True
100
  except Exception as e:
101
  error_str = str(e)
102
- # Check if it's just a version parsing error (non-fatal for CockroachDB)
103
  if "Could not determine version" in error_str:
104
- # Version parsing failed, but try to create tables anyway
105
- # CockroachDB connection works, just version string format is different
106
- try:
107
- Base.metadata.create_all(bind=engine)
108
- print("✓ CockroachDB connected and tables created (version parsing issue ignored)")
109
- return True
110
- except Exception as e2:
111
- print(f"Database table creation failed: {e2}")
112
- return False
113
  else:
114
  print(f"Database connection failed: {e}")
115
  return False
 
1
  import os
2
+ from sqlalchemy import create_engine, text
3
  from sqlalchemy.orm import sessionmaker, declarative_base
4
  from sqlalchemy.pool import NullPool
5
+
6
+ # Try to use CockroachDB dialect if available
7
+ try:
8
+ import cockroachdb.sqlalchemy.dialect
9
+ COCKROACHDB_AVAILABLE = True
10
+ except ImportError:
11
+ COCKROACHDB_AVAILABLE = False
12
 
13
  # Get database URL from environment variable
14
  # Default to SQLite for local development if not set
 
19
 
20
  # For CockroachDB, we need to handle SSL and connection pooling
21
  if DATABASE_URL.startswith("postgresql://") or DATABASE_URL.startswith("postgres://"):
22
+ # Check if this is a CockroachDB connection
23
+ is_cockroach = "cockroachlabs" in DATABASE_URL.lower()
24
+
25
  # CockroachDB connection - use NullPool to avoid connection issues
26
  # CockroachDB requires SSL, so we ensure sslmode is set
27
  # Use 'require' mode which uses SSL but doesn't require certificate file
28
  # For production with certificate, use 'verify-full' and provide sslrootcert
 
29
  cert_path = os.path.expanduser("~/.postgresql/root.crt")
30
 
31
  if "sslmode" not in DATABASE_URL:
 
38
  DATABASE_URL = DATABASE_URL.replace("sslmode=verify-full", "sslmode=require")
39
  print("⚠ Certificate file not found, using sslmode=require instead of verify-full")
40
 
41
+ # Use CockroachDB dialect if available and this is a CockroachDB connection
42
+ if is_cockroach and COCKROACHDB_AVAILABLE:
43
+ # Replace postgresql:// with cockroachdb:// to use CockroachDB dialect
44
+ DATABASE_URL = DATABASE_URL.replace("postgresql://", "cockroachdb://", 1)
45
+ DATABASE_URL = DATABASE_URL.replace("postgres://", "cockroachdb://", 1)
 
 
 
 
46
 
47
+ # Configure engine
48
  engine = create_engine(
49
  DATABASE_URL,
50
  poolclass=NullPool, # CockroachDB works better with NullPool
51
  echo=False, # Set to True for SQL query debugging
52
+ connect_args={} # No special connect args needed
53
  )
 
 
 
 
 
 
 
 
 
 
54
  else:
55
  # SQLite for local development
56
  engine = create_engine(
 
75
  try:
76
  from app.models import User, Integration, Asset, Post, Campaign
77
 
78
+ # Try to create tables
79
  # For CockroachDB, version parsing may fail but connection still works
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  Base.metadata.create_all(bind=engine)
81
+ print("✓ Database tables created successfully")
82
  return True
83
  except Exception as e:
84
  error_str = str(e)
85
+ # Check if it's a version parsing error (non-fatal for CockroachDB)
86
  if "Could not determine version" in error_str:
87
+ # Version parsing failed, but CockroachDB connection works
88
+ # SQLAlchemy will still function, just can't parse version string
89
+ # Tables will be created on first actual database operation
90
+ print("⚠ CockroachDB version parsing issue (non-fatal)")
91
+ print("✓ Database connection works - tables will be created on first use")
92
+ return True # Connection works, return True
 
 
 
93
  else:
94
  print(f"Database connection failed: {e}")
95
  return False
backend/requirements.txt CHANGED
@@ -10,4 +10,5 @@ python-jose[cryptography]
10
  passlib[bcrypt]
11
  sqlalchemy
12
  alembic
13
- psycopg2-binary
 
 
10
  passlib[bcrypt]
11
  sqlalchemy
12
  alembic
13
+ psycopg2-binary
14
+ sqlalchemy-cockroachdb