Skip to content

Instantly share code, notes, and snippets.

@gmolveau
Last active May 6, 2024 17:55
Show Gist options
  • Star 31 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save gmolveau/7caeeefe637679005a7bb9ae1b5e421e to your computer and use it in GitHub Desktop.
Save gmolveau/7caeeefe637679005a7bb9ae1b5e421e to your computer and use it in GitHub Desktop.
sqlalchemy uuid for sqlite
########################
# UUID for SQLite hack #
########################
from sqlalchemy.types import TypeDecorator, CHAR
from sqlalchemy.dialects.postgresql import UUID
import uuid
class GUID(TypeDecorator):
"""Platform-independent GUID type.
Uses PostgreSQL's UUID type, otherwise uses
CHAR(32), storing as stringified hex values.
"""
impl = CHAR
def load_dialect_impl(self, dialect):
if dialect.name == 'postgresql':
return dialect.type_descriptor(UUID())
else:
return dialect.type_descriptor(CHAR(32))
def process_bind_param(self, value, dialect):
if value is None:
return value
elif dialect.name == 'postgresql':
return str(value)
else:
if not isinstance(value, uuid.UUID):
return "%.32x" % uuid.UUID(value).int
else:
# hexstring
return "%.32x" % value.int
def process_result_value(self, value, dialect):
if value is None:
return value
else:
if not isinstance(value, uuid.UUID):
value = uuid.UUID(value)
return value
class Base(db.Model):
__abstract__ = True
id = db.Column(GUID(), primary_key=True, default=lambda: str(uuid.uuid4()))
created_at = db.Column(db.DateTime, default=db.func.current_timestamp())
updated_at = db.Column(db.DateTime,
default=db.func.current_timestamp(),
onupdate=db.func.current_timestamp())
class User(Base):
__tablename__ = 'users'
username = db.Column(db.String, nullable=False, unique=True)
email = db.Column(db.String, nullable=False, unique=True)
encrypted_password = db.Column(db.String, nullable=False)
def set_password(self, password):
self.encrypted_password = bc.generate_password_hash(password)
def verify_password(self, password):
return bc.check_password_hash(self.encrypted_password, password)
@TomerHeber
Copy link

TomerHeber commented May 6, 2022

This almost works.
Missing sort_key_function

This is my version:

class GUID(TypeDecorator):
    """Platform-independent GUID type.
    Uses PostgreSQL's UUID type, otherwise uses
    CHAR(32), storing as stringified hex values.
    """

    impl = CHAR
    cache_ok = True

    def load_dialect_impl(self, dialect):
        if dialect.name == "postgresql":
            return dialect.type_descriptor(UUID())
        else:
            return dialect.type_descriptor(CHAR(32))

    def process_bind_param(self, value, dialect):
        if value is None:
            return value
        elif dialect.name == "postgresql":
            return str(value)
        else:
            if not isinstance(value, uuid.UUID):
                return "%.32x" % uuid.UUID(value).int
            else:
                # hexstring
                return "%.32x" % value.int
    
    def _uuid_value(self, value):
        if value is None:
            return value
        else:
            if not isinstance(value, uuid.UUID):
                value = uuid.UUID(value)
            return value         

    def process_result_value(self, value, dialect):
        return self._uuid_value(value)

    def sort_key_function(self, value):
        return self._uuid_value(value)

@splint3rsec
Copy link

Awesome! Also you might consider changing the name of process_result_value to something else. :)

@tinynakji
Copy link

Thank you, this was useful!

@bfontaine
Copy link

@splint3rsec: why so? This is needed by SQLAlchemy.

@thomas1989
Copy link

crazy creative workaround. thx for your work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment