From f40e734642c8128d0151ecc3016e34c99caf64e2 Mon Sep 17 00:00:00 2001 From: Donald Stufft Date: Wed, 22 Jul 2015 14:22:47 -0400 Subject: [PATCH] Map more of the database into the ORM --- warehouse/legacy/tables.py | 35 --------- ...ff0c99c94_add_primary_key_to_dependency.py | 41 ++++++++++ warehouse/packaging/models.py | 77 +++++++++++++++++++ 3 files changed, 118 insertions(+), 35 deletions(-) create mode 100644 warehouse/migrations/versions/5ff0c99c94_add_primary_key_to_dependency.py diff --git a/warehouse/legacy/tables.py b/warehouse/legacy/tables.py index 380f0c97265a..47593809e5d2 100644 --- a/warehouse/legacy/tables.py +++ b/warehouse/legacy/tables.py @@ -457,41 +457,6 @@ Index("rego_otk_otk_idx", rego_otk.c.otk) -release_dependencies = Table( - "release_dependencies", - db.metadata, - - Column("name", Text()), - Column("version", Text()), - Column("kind", Integer()), - Column("specifier", Text()), - - ForeignKeyConstraint( - ["name", "version"], - ["releases.name", "releases.version"], - onupdate="CASCADE", - ), -) - - -Index("rel_dep_name_idx", release_dependencies.c.name) - - -Index( - "rel_dep_name_version_idx", - release_dependencies.c.name, - release_dependencies.c.version, -) - - -Index( - "rel_dep_name_version_kind_idx", - release_dependencies.c.name, - release_dependencies.c.version, - release_dependencies.c.kind, -) - - release_requires_python = Table( "release_requires_python", db.metadata, diff --git a/warehouse/migrations/versions/5ff0c99c94_add_primary_key_to_dependency.py b/warehouse/migrations/versions/5ff0c99c94_add_primary_key_to_dependency.py new file mode 100644 index 000000000000..f26f96252ccc --- /dev/null +++ b/warehouse/migrations/versions/5ff0c99c94_add_primary_key_to_dependency.py @@ -0,0 +1,41 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +Add primary key to Dependency + +Revision ID: 5ff0c99c94 +Revises: 312040efcfe +Create Date: 2015-07-20 19:50:55.153532 +""" + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +revision = "5ff0c99c94" +down_revision = "312040efcfe" + + +def upgrade(): + op.add_column( + "release_dependencies", + sa.Column( + "id", + postgresql.UUID(as_uuid=True), + server_default=sa.text("gen_random_uuid()"), + nullable=False, + ), + ) + + +def downgrade(): + op.drop_column("release_dependencies", "id") diff --git a/warehouse/packaging/models.py b/warehouse/packaging/models.py index f72ddc1e347f..179caab5c3fd 100644 --- a/warehouse/packaging/models.py +++ b/warehouse/packaging/models.py @@ -10,6 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import enum + from citext import CIText from pyramid.threadlocal import get_current_request from sqlalchemy import ( @@ -118,6 +120,55 @@ def documentation_url(self): return request.route_url("legacy.docs", project=self.name) +class DependencyKind(enum.IntEnum): + + requires = 1 + provides = 2 + obsoletes = 3 + requires_dist = 4 + provides_dist = 5 + obsoletes_dist = 6 + requires_external = 7 + + # TODO: Move project URLs into their own table, since they are not actually + # a "dependency". + project_url = 8 + + +class Dependency(db.Model): + + __tablename__ = "release_dependencies" + __table_args__ = ( + Index("rel_dep_name_idx", "name"), + Index("rel_dep_name_version_idx", "name", "version"), + Index("rel_dep_name_version_kind_idx", "name", "version", "kind"), + ForeignKeyConstraint( + ["name", "version"], + ["releases.name", "releases.version"], + onupdate="CASCADE", + ), + ) + __repr__ = make_repr("name", "version", "kind", "specifier") + + name = Column(Text) + version = Column(Text) + kind = Column(Integer) + specifier = Column(Text) + + +def _dependency_relation(kind): + return orm.relationship( + "Dependency", + primaryjoin=lambda: sql.and_( + Release.name == Dependency.name, + Release.version == Dependency.version, + Dependency.kind == kind.value, + ), + lazy=False, + viewonly=True, + ) + + class Release(db.ModelBase): __tablename__ = "releases" @@ -188,6 +239,32 @@ def __table_args__(cls): # noqa order_by=lambda: File.filename, ) + dependencies = orm.relationship("Dependency") + + _requires = _dependency_relation(DependencyKind.requires) + requires = association_proxy("_requires", "specifier") + + _provides = _dependency_relation(DependencyKind.provides) + provides = association_proxy("_provides", "specifier") + + _obsoletes = _dependency_relation(DependencyKind.obsoletes) + obsoletes = association_proxy("_obsoletes", "specifier") + + _requires_dist = _dependency_relation(DependencyKind.requires_dist) + requires_dist = association_proxy("_requires_dist", "specifier") + + _provides_dist = _dependency_relation(DependencyKind.provides_dist) + provides_dist = association_proxy("_provides_dist", "specifier") + + _obsoletes_dist = _dependency_relation(DependencyKind.obsoletes_dist) + obsoletes_dist = association_proxy("_obsoletes_dist", "specifier") + + _requires_external = _dependency_relation(DependencyKind.requires_external) + requires_external = association_proxy("_requires_external", "specifier") + + _project_urls = _dependency_relation(DependencyKind.project_url) + project_urls = association_proxy("_project_urls", "specifier") + class File(db.Model):