I18n через jsonb-поля

This commit is contained in:
2025-04-24 15:53:05 +04:00
parent 35b571eb57
commit 31ad99ade5
33 changed files with 409 additions and 264 deletions
+59 -23
View File
@@ -1,4 +1,8 @@
using Microsoft.EntityFrameworkCore.Migrations;
using Pf2eModel.Model.Structure;
using static LinqToDB.Common.Configuration;
using static System.Runtime.InteropServices.JavaScript.JSType;
using System.Buffers;
#nullable disable
@@ -22,46 +26,76 @@ BEGIN
|| ' CASCADE;'
FROM pg_tables
WHERE schemaname = 'public'
AND tablename != '__EFMigrationsHistory'
AND tablename != '__EFMigrationsHistory'
);
END
$func$;
""");
migrationBuilder.Sql("""
CREATE OR REPLACE FUNCTION f_drop_tables()
RETURNS void
LANGUAGE plpgsql AS
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE
(SELECT 'DROP TABLE '
|| string_agg(format('%I.%I', schemaname, tablename), ', ')
|| ' CASCADE;'
FROM pg_tables
WHERE schemaname = 'public'
);
EXECUTE
(SELECT 'DROP TABLE '
|| string_agg(format('%I.%I', schemaname, tablename), ', ')
|| ' CASCADE;'
FROM pg_tables
WHERE schemaname = 'public'
);
END
$func$;
""");
migrationBuilder.Sql("""
CREATE OR REPLACE FUNCTION f_permission_tables(_username text)
RETURNS void
LANGUAGE plpgsql AS
$func$
RETURNS void
LANGUAGE plpgsql AS
$func$
DECLARE
_tbl text;
_sch text;
_tbl text;
_sch text;
BEGIN
FOR _sch, _tbl IN
SELECT schemaname, tablename
FROM pg_tables
WHERE schemaname = 'public'
LOOP
EXECUTE format('ALTER TABLE %I.%I OWNER TO %I', _sch, _tbl, _username);
END LOOP;
FOR _sch, _tbl IN
SELECT schemaname, tablename
FROM pg_tables
WHERE schemaname = 'public'
LOOP
EXECUTE format('ALTER TABLE %I.%I OWNER TO %I', _sch, _tbl, _username);
END LOOP;
END
$func$;
""");
"""
);
migrationBuilder.Sql("""
CREATE OR REPLACE FUNCTION locale_search(data jsonb, search_value text)
RETURNS boolean
LANGUAGE plpgsql AS
$func$
BEGIN
RETURN jsonb_path_exists(data, '$.** ? (@ == $val)', jsonb_build_object('val', search_value));
END;
$func$;
"""
);
migrationBuilder.Sql("""
CREATE OR REPLACE FUNCTION locale_search_array(data jsonb, search_values text[])
RETURNS boolean
LANGUAGE plpgsql AS
$func$
BEGIN
RETURN EXISTS (
SELECT 1
FROM unnest(search_values) AS val
WHERE jsonb_path_exists(data, '$.** ? (@ == $val)', jsonb_build_object('val', val))
);
END;
$func$;
"""
);
}
/// <inheritdoc />
@@ -70,5 +104,7 @@ $func$;
migrationBuilder.Sql("DROP FUNCTION f_truncate_tables;");
migrationBuilder.Sql("DROP FUNCTION f_drop_tables;");
migrationBuilder.Sql("DROP FUNCTION f_permission_tables;");
migrationBuilder.Sql("DROP FUNCTION locale_search;");
migrationBuilder.Sql("DROP FUNCTION locale_search_array;");
}
}
@@ -13,7 +13,7 @@ using Pf2eModel.Model.Enum;
namespace Pf2eModel.Migrations
{
[DbContext(typeof(Pf2eDbContext))]
[Migration("20250421123520_1")]
[Migration("20250424112427_1")]
partial class _1
{
/// <inheritdoc />
@@ -25,7 +25,6 @@ namespace Pf2eModel.Migrations
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "action_category", new[] { "unknown", "archetype", "class-feature", "class-feat", "offensive", "defensive", "interaction", "familiar", "army_tactic", "army_war_action", "kingdom_activity", "kingdom_feat", "kingdom_feature" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "alias_type", new[] { "legacy", "english", "legacy_english", "hobby", "other" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "ancestry_vision", new[] { "normal", "low-light-vision", "dark-vision" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "attribute_values", new[] { "free", "str", "dex", "con", "int", "wis", "cha" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "class_progression_type", new[] { "entity", "ancestry_feat", "class_feat", "general_feat", "skill_feat", "skill_increase" });
@@ -37,6 +36,7 @@ namespace Pf2eModel.Migrations
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "entity_type", new[] { "unknown", "trait", "action", "ancestry", "archetype", "background", "backpack", "campaign_feature", "class", "condition", "deity", "feat", "heritage", "spell", "language" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "feat_action_type", new[] { "passive", "action", "reaction", "free" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "feat_category", new[] { "uncategorized", "ancestry-feature", "class-feature", "calling", "class", "skill", "general", "ancestry", "bonus", "deityboon", "curse", "pfsboon", "campaign-feature" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "locale_type", new[] { "english", "legacy_english", "russian", "legacy", "hobby", "other" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "size", new[] { "tiny", "small", "medium", "large" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "source_category", new[] { "rulebook", "adventure-path", "lost-omens", "adventures", "comics", "blog-posts", "society" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "spell_area_type", new[] { "burst", "emanation", "cone", "line", "square", "cube", "cylinder" });
@@ -142,8 +142,7 @@ namespace Pf2eModel.Migrations
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnType("jsonb")
.HasColumnName("name")
.HasColumnOrder(2)
.HasComment("Отображаемое имя");
@@ -173,31 +172,6 @@ namespace Pf2eModel.Migrations
b.ToTable("entities", (string)null);
});
modelBuilder.Entity("Pf2eModel.Model.Base.EntityAlias", b =>
{
b.Property<int>("EntityId")
.HasColumnType("integer")
.HasColumnName("entity_id")
.HasColumnOrder(1);
b.Property<AliasType>("Type")
.HasColumnType("alias_type")
.HasColumnName("type")
.HasColumnOrder(2);
b.Property<string>("Alias")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("alias")
.HasColumnOrder(3);
b.HasKey("EntityId", "Type")
.HasName("pk_entity_aliases");
b.ToTable("entity_aliases", (string)null);
});
modelBuilder.Entity("Pf2eModel.Model.Base.Keywords.Keyword", b =>
{
b.Property<int>("Id")
@@ -1536,18 +1510,6 @@ namespace Pf2eModel.Migrations
.HasConstraintName("fk_entity_trait_traits_traits_id");
});
modelBuilder.Entity("Pf2eModel.Model.Base.EntityAlias", b =>
{
b.HasOne("Pf2eModel.Model.Base.Entity", "Entity")
.WithMany("Aliases")
.HasForeignKey("EntityId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_entity_aliases_entities_entity_id");
b.Navigation("Entity");
});
modelBuilder.Entity("Pf2eModel.Model.Base.Keywords.KeywordAlias", b =>
{
b.HasOne("Pf2eModel.Model.Base.Keywords.Keyword", "Keyword")
@@ -2056,8 +2018,6 @@ namespace Pf2eModel.Migrations
modelBuilder.Entity("Pf2eModel.Model.Base.Entity", b =>
{
b.Navigation("Aliases");
b.Navigation("Externals");
b.Navigation("Sources");
@@ -15,7 +15,6 @@ namespace Pf2eModel.Migrations
{
migrationBuilder.AlterDatabase()
.Annotation("Npgsql:Enum:action_category", "unknown,archetype,class-feature,class-feat,offensive,defensive,interaction,familiar,army_tactic,army_war_action,kingdom_activity,kingdom_feat,kingdom_feature")
.Annotation("Npgsql:Enum:alias_type", "legacy,english,legacy_english,hobby,other")
.Annotation("Npgsql:Enum:ancestry_vision", "normal,low-light-vision,dark-vision")
.Annotation("Npgsql:Enum:attribute_values", "free,str,dex,con,int,wis,cha")
.Annotation("Npgsql:Enum:class_progression_type", "entity,ancestry_feat,class_feat,general_feat,skill_feat,skill_increase")
@@ -27,6 +26,7 @@ namespace Pf2eModel.Migrations
.Annotation("Npgsql:Enum:entity_type", "unknown,trait,action,ancestry,archetype,background,backpack,campaign_feature,class,condition,deity,feat,heritage,spell,language")
.Annotation("Npgsql:Enum:feat_action_type", "passive,action,reaction,free")
.Annotation("Npgsql:Enum:feat_category", "uncategorized,ancestry-feature,class-feature,calling,class,skill,general,ancestry,bonus,deityboon,curse,pfsboon,campaign-feature")
.Annotation("Npgsql:Enum:locale_type", "english,legacy_english,russian,legacy,hobby,other")
.Annotation("Npgsql:Enum:size", "tiny,small,medium,large")
.Annotation("Npgsql:Enum:source_category", "rulebook,adventure-path,lost-omens,adventures,comics,blog-posts,society")
.Annotation("Npgsql:Enum:spell_area_type", "burst,emanation,cone,line,square,cube,cylinder")
@@ -41,7 +41,7 @@ namespace Pf2eModel.Migrations
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
name = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false, comment: "Отображаемое имя"),
name = table.Column<string>(type: "jsonb", nullable: false, comment: "Отображаемое имя"),
type = table.Column<EntityType>(type: "entity_type", nullable: false, comment: "Тип объекта"),
slug = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false, comment: "Часть имени в URL"),
img = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false, comment: "Изображение объекта"),
@@ -250,25 +250,6 @@ namespace Pf2eModel.Migrations
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "entity_aliases",
columns: table => new
{
entity_id = table.Column<int>(type: "integer", nullable: false),
type = table.Column<AliasType>(type: "alias_type", nullable: false),
alias = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_entity_aliases", x => new { x.entity_id, x.type });
table.ForeignKey(
name: "fk_entity_aliases_entities_entity_id",
column: x => x.entity_id,
principalTable: "entities",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "feats",
columns: table => new
@@ -1189,9 +1170,6 @@ namespace Pf2eModel.Migrations
migrationBuilder.DropTable(
name: "deity_weapons");
migrationBuilder.DropTable(
name: "entity_aliases");
migrationBuilder.DropTable(
name: "entity_externals");
@@ -22,7 +22,6 @@ namespace Pf2eModel.Migrations
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "action_category", new[] { "unknown", "archetype", "class-feature", "class-feat", "offensive", "defensive", "interaction", "familiar", "army_tactic", "army_war_action", "kingdom_activity", "kingdom_feat", "kingdom_feature" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "alias_type", new[] { "legacy", "english", "legacy_english", "hobby", "other" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "ancestry_vision", new[] { "normal", "low-light-vision", "dark-vision" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "attribute_values", new[] { "free", "str", "dex", "con", "int", "wis", "cha" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "class_progression_type", new[] { "entity", "ancestry_feat", "class_feat", "general_feat", "skill_feat", "skill_increase" });
@@ -34,6 +33,7 @@ namespace Pf2eModel.Migrations
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "entity_type", new[] { "unknown", "trait", "action", "ancestry", "archetype", "background", "backpack", "campaign_feature", "class", "condition", "deity", "feat", "heritage", "spell", "language" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "feat_action_type", new[] { "passive", "action", "reaction", "free" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "feat_category", new[] { "uncategorized", "ancestry-feature", "class-feature", "calling", "class", "skill", "general", "ancestry", "bonus", "deityboon", "curse", "pfsboon", "campaign-feature" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "locale_type", new[] { "english", "legacy_english", "russian", "legacy", "hobby", "other" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "size", new[] { "tiny", "small", "medium", "large" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "source_category", new[] { "rulebook", "adventure-path", "lost-omens", "adventures", "comics", "blog-posts", "society" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "spell_area_type", new[] { "burst", "emanation", "cone", "line", "square", "cube", "cylinder" });
@@ -139,8 +139,7 @@ namespace Pf2eModel.Migrations
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnType("jsonb")
.HasColumnName("name")
.HasColumnOrder(2)
.HasComment("Отображаемое имя");
@@ -170,31 +169,6 @@ namespace Pf2eModel.Migrations
b.ToTable("entities", (string)null);
});
modelBuilder.Entity("Pf2eModel.Model.Base.EntityAlias", b =>
{
b.Property<int>("EntityId")
.HasColumnType("integer")
.HasColumnName("entity_id")
.HasColumnOrder(1);
b.Property<AliasType>("Type")
.HasColumnType("alias_type")
.HasColumnName("type")
.HasColumnOrder(2);
b.Property<string>("Alias")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("alias")
.HasColumnOrder(3);
b.HasKey("EntityId", "Type")
.HasName("pk_entity_aliases");
b.ToTable("entity_aliases", (string)null);
});
modelBuilder.Entity("Pf2eModel.Model.Base.Keywords.Keyword", b =>
{
b.Property<int>("Id")
@@ -1533,18 +1507,6 @@ namespace Pf2eModel.Migrations
.HasConstraintName("fk_entity_trait_traits_traits_id");
});
modelBuilder.Entity("Pf2eModel.Model.Base.EntityAlias", b =>
{
b.HasOne("Pf2eModel.Model.Base.Entity", "Entity")
.WithMany("Aliases")
.HasForeignKey("EntityId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_entity_aliases_entities_entity_id");
b.Navigation("Entity");
});
modelBuilder.Entity("Pf2eModel.Model.Base.Keywords.KeywordAlias", b =>
{
b.HasOne("Pf2eModel.Model.Base.Keywords.Keyword", "Keyword")
@@ -2053,8 +2015,6 @@ namespace Pf2eModel.Migrations
modelBuilder.Entity("Pf2eModel.Model.Base.Entity", b =>
{
b.Navigation("Aliases");
b.Navigation("Externals");
b.Navigation("Sources");