// Kyoo - A portable and vast media library solution. // Copyright (c) Kyoo. // // See AUTHORS.md and LICENSE file in the project root for full license information. // // Kyoo is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // any later version. // // Kyoo is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . using System; using System.Globalization; using System.Linq.Expressions; using System.Reflection; using EFCore.NamingConventions.Internal; using Kyoo.Abstractions.Models; using Kyoo.Utils; using Microsoft.EntityFrameworkCore; using Npgsql; namespace Kyoo.Postgresql { /// /// A postgresql implementation of . /// public class PostgresContext : DatabaseContext { /// /// The connection string to use. /// private readonly string _connection; /// /// Is this instance in debug mode? /// private readonly bool _debugMode; /// /// Should the configure step be skipped? This is used when the database is created via DbContextOptions. /// private readonly bool _skipConfigure; // TOOD: This needs ot be updated but ef-core still does not offer a way to use this. [Obsolete] static PostgresContext() { NpgsqlConnection.GlobalTypeMapper.MapEnum(); NpgsqlConnection.GlobalTypeMapper.MapEnum(); } /// /// A basic constructor that set default values (query tracker behaviors, mapping enums...) /// public PostgresContext() { } /// /// Create a new using specific options /// /// The options to use. public PostgresContext(DbContextOptions options) : base(options) { _skipConfigure = true; } /// /// A basic constructor that set default values (query tracker behaviors, mapping enums...) /// /// The connection string to use /// Is this instance in debug mode? public PostgresContext(string connection, bool debugMode) { _connection = connection; _debugMode = debugMode; } /// /// Set connection information for this database context /// /// An option builder to fill. protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (!_skipConfigure) { optionsBuilder.UseNpgsql(); if (_debugMode) optionsBuilder.EnableDetailedErrors().EnableSensitiveDataLogging(); } optionsBuilder.UseSnakeCaseNamingConvention(); base.OnConfiguring(optionsBuilder); } /// /// Set database parameters to support every types of Kyoo. /// /// The database's model builder. protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.HasPostgresEnum(); modelBuilder.HasPostgresEnum(); modelBuilder.Entity() .ToView("library_items") .HasKey(x => x.ID); modelBuilder.Entity() .Property(x => x.ExtraData) .HasColumnType("jsonb"); modelBuilder.Entity() .Property(x => x.Images) .HasColumnType("jsonb"); modelBuilder.Entity() .Property(x => x.Images) .HasColumnType("jsonb"); modelBuilder.Entity() .Property(x => x.Images) .HasColumnType("jsonb"); modelBuilder.Entity() .Property(x => x.Images) .HasColumnType("jsonb"); modelBuilder.Entity() .Property(x => x.Images) .HasColumnType("jsonb"); modelBuilder.Entity() .Property(x => x.Images) .HasColumnType("jsonb"); modelBuilder.Entity() .Property(x => x.Images) .HasColumnType("jsonb"); modelBuilder.Entity() .Property(x => x.Images) .HasColumnType("jsonb"); base.OnModelCreating(modelBuilder); } /// protected override string MetadataName() { SnakeCaseNameRewriter rewriter = new(CultureInfo.InvariantCulture); return rewriter.RewriteName(typeof(T).Name + nameof(MetadataID)); } /// protected override string LinkName() { SnakeCaseNameRewriter rewriter = new(CultureInfo.InvariantCulture); return rewriter.RewriteName("Link" + typeof(T).Name + typeof(T2).Name); } /// protected override string LinkNameFk() { SnakeCaseNameRewriter rewriter = new(CultureInfo.InvariantCulture); return rewriter.RewriteName(typeof(T).Name + "ID"); } /// protected override bool IsDuplicateException(Exception ex) { return ex.InnerException is PostgresException { SqlState: PostgresErrorCodes.UniqueViolation }; } /// public override Expression> Like(Expression> query, string format) { MethodInfo iLike = MethodOfUtils.MethodOf(EF.Functions.ILike); MethodCallExpression call = Expression.Call(iLike, Expression.Constant(EF.Functions), query.Body, Expression.Constant(format)); return Expression.Lambda>(call, query.Parameters); } } }