From f087c5a85511738f1161a400cd4e72911cc5be4d Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Sat, 18 May 2024 16:28:43 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F=20Naming=20conventions=20?= =?UTF-8?q?for=20link=20tables,=20protecting=20deletion=20in=20link=20tabl?= =?UTF-8?q?es,=20maintaining=20integrity=20upon=20label=20&=20feature=20re?= =?UTF-8?q?names=20(#383)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ♻️ Also indicate whether semantic identifiers were used * 💚 Fix * 🍱 Add squashed version --- ...0049_rename_type_feature_dtype_and_more.py | 2 +- ...ureset_feature_ref_is_semantic_and_more.py | 191 ++++++++++++++++++ .../{0049_squashed.py => 0050_squashed.py} | 45 ++++- lnschema_core/models.py | 50 +++-- 4 files changed, 263 insertions(+), 25 deletions(-) create mode 100644 lnschema_core/migrations/0050_artifactfeatureset_feature_ref_is_semantic_and_more.py rename lnschema_core/migrations/{0049_squashed.py => 0050_squashed.py} (94%) diff --git a/lnschema_core/migrations/0049_rename_type_feature_dtype_and_more.py b/lnschema_core/migrations/0049_rename_type_feature_dtype_and_more.py index 2af551e0..5285ae79 100644 --- a/lnschema_core/migrations/0049_rename_type_feature_dtype_and_more.py +++ b/lnschema_core/migrations/0049_rename_type_feature_dtype_and_more.py @@ -25,7 +25,7 @@ class Migration(migrations.Migration): migrations.RunSQL( """ -- Replace all occurrences of "core." in dtype with an empty string - UPDATE your_app_name_feature + UPDATE lnschema_core_feature SET dtype = REPLACE(dtype, 'core.', ''); """ ), diff --git a/lnschema_core/migrations/0050_artifactfeatureset_feature_ref_is_semantic_and_more.py b/lnschema_core/migrations/0050_artifactfeatureset_feature_ref_is_semantic_and_more.py new file mode 100644 index 00000000..5c1a5542 --- /dev/null +++ b/lnschema_core/migrations/0050_artifactfeatureset_feature_ref_is_semantic_and_more.py @@ -0,0 +1,191 @@ +# Generated by Django 5.0.6 on 2024-05-18 13:44 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("lnschema_core", "0049_rename_type_feature_dtype_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="artifactfeatureset", + name="feature_ref_is_semantic", + field=models.BooleanField(default=None, null=True), + ), + migrations.AddField( + model_name="artifactulabel", + name="feature_ref_is_name", + field=models.BooleanField(default=None, null=True), + ), + migrations.AddField( + model_name="artifactulabel", + name="ulabel_ref_is_name", + field=models.BooleanField(default=None, null=True), + ), + migrations.AddField( + model_name="collectionfeatureset", + name="feature_ref_is_semantic", + field=models.BooleanField(default=None, null=True), + ), + migrations.AddField( + model_name="collectionulabel", + name="feature_ref_is_name", + field=models.BooleanField(default=None, null=True), + ), + migrations.AddField( + model_name="collectionulabel", + name="ulabel_ref_is_name", + field=models.BooleanField(default=None, null=True), + ), + migrations.AlterField( + model_name="artifactfeatureset", + name="artifact", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="feature_set_links", + to="lnschema_core.artifact", + ), + ), + migrations.AlterField( + model_name="artifactfeatureset", + name="feature_set", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="artifact_links", + to="lnschema_core.featureset", + ), + ), + migrations.AlterField( + model_name="artifactfeaturevalue", + name="artifact", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="+", + to="lnschema_core.artifact", + ), + ), + migrations.AlterField( + model_name="artifactfeaturevalue", + name="feature_value", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="+", + to="lnschema_core.featurevalue", + ), + ), + migrations.AlterField( + model_name="artifactulabel", + name="artifact", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="ulabel_links", + to="lnschema_core.artifact", + ), + ), + migrations.AlterField( + model_name="artifactulabel", + name="feature", + field=models.ForeignKey( + default=None, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="artifactulabel_links", + to="lnschema_core.feature", + ), + ), + migrations.AlterField( + model_name="artifactulabel", + name="ulabel", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="artifact_links", + to="lnschema_core.ulabel", + ), + ), + migrations.AlterField( + model_name="collectionartifact", + name="artifact", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="+", + to="lnschema_core.artifact", + ), + ), + migrations.AlterField( + model_name="collectionartifact", + name="collection", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="+", + to="lnschema_core.collection", + ), + ), + migrations.AlterField( + model_name="collectionfeatureset", + name="collection", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="feature_set_links", + to="lnschema_core.collection", + ), + ), + migrations.AlterField( + model_name="collectionfeatureset", + name="feature_set", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="collection_links", + to="lnschema_core.featureset", + ), + ), + migrations.AlterField( + model_name="collectionulabel", + name="collection", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="ulabel_links", + to="lnschema_core.collection", + ), + ), + migrations.AlterField( + model_name="collectionulabel", + name="feature", + field=models.ForeignKey( + default=None, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="collectionulabel_links", + to="lnschema_core.feature", + ), + ), + migrations.AlterField( + model_name="collectionulabel", + name="ulabel", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="collection_links", + to="lnschema_core.ulabel", + ), + ), + migrations.AlterField( + model_name="runparamvalue", + name="param_value", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="+", + to="lnschema_core.paramvalue", + ), + ), + migrations.AlterField( + model_name="runparamvalue", + name="run", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="+", + to="lnschema_core.run", + ), + ), + ] diff --git a/lnschema_core/migrations/0049_squashed.py b/lnschema_core/migrations/0050_squashed.py similarity index 94% rename from lnschema_core/migrations/0049_squashed.py rename to lnschema_core/migrations/0050_squashed.py index ef2a0d32..e7f08490 100644 --- a/lnschema_core/migrations/0049_squashed.py +++ b/lnschema_core/migrations/0050_squashed.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.6 on 2024-05-17 20:40 +# Generated by Django 5.0.6 on 2024-05-18 13:50 import django.db.models.deletion from django.db import migrations, models @@ -39,6 +39,7 @@ class Migration(migrations.Migration): ("lnschema_core", "0047_featurevalue_artifactfeaturevalue_and_more"), ("lnschema_core", "0048_alter_artifactulabel_feature_and_more"), ("lnschema_core", "0049_rename_type_feature_dtype_and_more"), + ("lnschema_core", "0050_artifactfeatureset_feature_ref_is_semantic_and_more"), ] dependencies = [] # type: ignore @@ -308,7 +309,8 @@ class Migration(migrations.Migration): ( "artifact", models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, + on_delete=django.db.models.deletion.PROTECT, + related_name="+", to="lnschema_core.artifact", ), ), @@ -316,6 +318,7 @@ class Migration(migrations.Migration): "collection", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, + related_name="+", to="lnschema_core.collection", ), ), @@ -388,17 +391,23 @@ class Migration(migrations.Migration): fields=[ ("id", models.BigAutoField(primary_key=True, serialize=False)), ("slot", models.CharField(default=None, max_length=50, null=True)), + ( + "feature_ref_is_semantic", + models.BooleanField(default=None, null=True), + ), ( "collection", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, + related_name="feature_set_links", to="lnschema_core.collection", ), ), ( "feature_set", models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, + on_delete=django.db.models.deletion.PROTECT, + related_name="collection_links", to="lnschema_core.featureset", ), ), @@ -422,17 +431,23 @@ class Migration(migrations.Migration): fields=[ ("id", models.BigAutoField(primary_key=True, serialize=False)), ("slot", models.CharField(default=None, max_length=40, null=True)), + ( + "feature_ref_is_semantic", + models.BooleanField(default=None, null=True), + ), ( "artifact", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, + related_name="feature_set_links", to="lnschema_core.artifact", ), ), ( "feature_set", models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, + on_delete=django.db.models.deletion.PROTECT, + related_name="artifact_links", to="lnschema_core.featureset", ), ), @@ -496,13 +511,15 @@ class Migration(migrations.Migration): "artifact", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, + related_name="+", to="lnschema_core.artifact", ), ), ( "feature_value", models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, + on_delete=django.db.models.deletion.PROTECT, + related_name="+", to="lnschema_core.featurevalue", ), ), @@ -666,7 +683,8 @@ class Migration(migrations.Migration): ( "param_value", models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, + on_delete=django.db.models.deletion.PROTECT, + related_name="+", to="lnschema_core.paramvalue", ), ), @@ -674,6 +692,7 @@ class Migration(migrations.Migration): "run", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, + related_name="+", to="lnschema_core.run", ), ), @@ -895,10 +914,13 @@ class Migration(migrations.Migration): name="CollectionULabel", fields=[ ("id", models.BigAutoField(primary_key=True, serialize=False)), + ("ulabel_ref_is_name", models.BooleanField(default=None, null=True)), + ("feature_ref_is_name", models.BooleanField(default=None, null=True)), ( "collection", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, + related_name="ulabel_links", to="lnschema_core.collection", ), ), @@ -908,13 +930,15 @@ class Migration(migrations.Migration): default=None, null=True, on_delete=django.db.models.deletion.PROTECT, + related_name="collectionulabel_links", to="lnschema_core.feature", ), ), ( "ulabel", models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, + on_delete=django.db.models.deletion.PROTECT, + related_name="collection_links", to="lnschema_core.ulabel", ), ), @@ -937,10 +961,13 @@ class Migration(migrations.Migration): name="ArtifactULabel", fields=[ ("id", models.BigAutoField(primary_key=True, serialize=False)), + ("ulabel_ref_is_name", models.BooleanField(default=None, null=True)), + ("feature_ref_is_name", models.BooleanField(default=None, null=True)), ( "artifact", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, + related_name="ulabel_links", to="lnschema_core.artifact", ), ), @@ -950,13 +977,15 @@ class Migration(migrations.Migration): default=None, null=True, on_delete=django.db.models.deletion.PROTECT, + related_name="artifactulabel_links", to="lnschema_core.feature", ), ), ( "ulabel", models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, + on_delete=django.db.models.deletion.PROTECT, + related_name="artifact_links", to="lnschema_core.ulabel", ), ), diff --git a/lnschema_core/models.py b/lnschema_core/models.py index eaa20e58..5be59420 100644 --- a/lnschema_core/models.py +++ b/lnschema_core/models.py @@ -2338,9 +2338,12 @@ class LinkORM: class ArtifactFeatureSet(Registry, LinkORM): id = models.BigAutoField(primary_key=True) - artifact = models.ForeignKey(Artifact, CASCADE) - feature_set = models.ForeignKey(FeatureSet, CASCADE) + artifact = models.ForeignKey(Artifact, CASCADE, related_name="feature_set_links") + feature_set = models.ForeignKey(FeatureSet, PROTECT, related_name="artifact_links") slot = CharField(max_length=40, null=True, default=None) + feature_ref_is_semantic = models.BooleanField( + null=True, default=None + ) # like Feature name or Gene symbol or CellMarker name class Meta: unique_together = ("artifact", "feature_set") @@ -2348,9 +2351,16 @@ class Meta: class CollectionFeatureSet(Registry, LinkORM): id = models.BigAutoField(primary_key=True) - collection = models.ForeignKey(Collection, CASCADE) - feature_set = models.ForeignKey(FeatureSet, CASCADE) + collection = models.ForeignKey( + Collection, CASCADE, related_name="feature_set_links" + ) + feature_set = models.ForeignKey( + FeatureSet, PROTECT, related_name="collection_links" + ) slot = CharField(max_length=50, null=True, default=None) + feature_ref_is_semantic = models.BooleanField( + null=True, default=None + ) # like Feature name or Gene symbol or CellMarker name class Meta: unique_together = ("collection", "feature_set") @@ -2358,8 +2368,8 @@ class Meta: class CollectionArtifact(Registry, LinkORM): id = models.BigAutoField(primary_key=True) - collection = models.ForeignKey(Collection, CASCADE) - artifact = models.ForeignKey(Artifact, CASCADE) + collection = models.ForeignKey(Collection, CASCADE, related_name="+") + artifact = models.ForeignKey(Artifact, PROTECT, related_name="+") class Meta: unique_together = ("collection", "artifact") @@ -2367,9 +2377,13 @@ class Meta: class ArtifactULabel(Registry, LinkORM): id = models.BigAutoField(primary_key=True) - artifact = models.ForeignKey(Artifact, CASCADE) - ulabel = models.ForeignKey(ULabel, CASCADE) - feature = models.ForeignKey(Feature, PROTECT, null=True, default=None) + artifact = models.ForeignKey(Artifact, CASCADE, related_name="ulabel_links") + ulabel = models.ForeignKey(ULabel, PROTECT, related_name="artifact_links") + feature = models.ForeignKey( + Feature, PROTECT, null=True, default=None, related_name="artifactulabel_links" + ) + ulabel_ref_is_name = models.BooleanField(null=True, default=None) + feature_ref_is_name = models.BooleanField(null=True, default=None) class Meta: unique_together = ("artifact", "ulabel") @@ -2377,9 +2391,13 @@ class Meta: class CollectionULabel(Registry, LinkORM): id = models.BigAutoField(primary_key=True) - collection = models.ForeignKey(Collection, CASCADE) - ulabel = models.ForeignKey(ULabel, CASCADE) - feature = models.ForeignKey(Feature, PROTECT, null=True, default=None) + collection = models.ForeignKey(Collection, CASCADE, related_name="ulabel_links") + ulabel = models.ForeignKey(ULabel, PROTECT, related_name="collection_links") + feature = models.ForeignKey( + Feature, PROTECT, null=True, default=None, related_name="collectionulabel_links" + ) + ulabel_ref_is_name = models.BooleanField(null=True, default=None) + feature_ref_is_name = models.BooleanField(null=True, default=None) class Meta: unique_together = ("collection", "ulabel") @@ -2387,8 +2405,8 @@ class Meta: class ArtifactFeatureValue(Registry, LinkORM): id = models.BigAutoField(primary_key=True) - artifact = models.ForeignKey(Artifact, CASCADE) - feature_value = models.ForeignKey(FeatureValue, CASCADE) + artifact = models.ForeignKey(Artifact, CASCADE, related_name="+") + feature_value = models.ForeignKey(FeatureValue, PROTECT, related_name="+") class Meta: unique_together = ("artifact", "feature_value") @@ -2396,8 +2414,8 @@ class Meta: class RunParamValue(Registry, LinkORM): id = models.BigAutoField(primary_key=True) - run = models.ForeignKey(Run, CASCADE) - param_value = models.ForeignKey(ParamValue, CASCADE) + run = models.ForeignKey(Run, CASCADE, related_name="+") + param_value = models.ForeignKey(ParamValue, PROTECT, related_name="+") class Meta: unique_together = ("run", "param_value")