first draft of zero.Sqlite extension

This commit is contained in:
2025-09-03 15:51:25 +02:00
parent f1c4dbf42c
commit 0e3794c6f0
7 changed files with 246 additions and 0 deletions
@@ -0,0 +1,33 @@
using System;
using System.Linq;
using System.Linq.Expressions;
using ServiceStack.OrmLite;
using zero.Extensions;
namespace zero.Sqlite;
public static class SqlExpressionExtensions
{
public static SqlExpression<T> Paging<T>(this SqlExpression<T> source, int pageNumber, int pageSize)
{
pageNumber = pageNumber.Limit(1, 10_000_000);
pageSize = pageSize.Limit(1, 1_000);
if (pageNumber <= 0 || pageSize <= 0)
{
throw new NotSupportedException("Both pageNumber and pageSize must be greater than zero");
}
return source.Skip((pageNumber - 1) * pageSize).Take(pageSize);
}
public static SqlExpression<T> WhereIf<T>(this SqlExpression<T> source, Expression<Func<T, bool>> predicate, bool condition, Expression<Func<T, bool>> elsePredicate = null)
{
if (condition)
{
return source.Where(predicate);
}
return elsePredicate != null ? source.Where(elsePredicate) : source;
}
}
+102
View File
@@ -0,0 +1,102 @@
using System;
using FluentValidation.Results;
using Microsoft.Extensions.DependencyInjection;
using System.Linq.Expressions;
using System.Security.Claims;
using System.Threading.Tasks;
using zero.Context;
using zero.Models;
using zero.Utils;
using zero.Validation;
namespace zero.Sqlite;
public partial class DbOperations : IDbOperations
{
protected IZeroContext Context { get; private set; }
protected FlavorOptions Flavors { get; private set; }
protected IServiceProvider Services { get; private set; }
public DbOperations(StoreContext context)
{
Context = context.Context;
Services = context.Services;
Flavors = context.Options.For<FlavorOptions>();
}
/// <inheritdoc />
public Task<string> GenerateId<T>(T model) where T : ZeroIdEntity
{
return Task.FromResult(IdGenerator.Create(12));
}
/// <inheritdoc />
public T AutoSetIds<T>(T model)
{
return IdGenerator.Autofill(model);
}
/// <inheritdoc />
public T PrepareForSave<T>(T model) where T : ZeroIdEntity
{
// set IDs
AutoSetIds(model);
if (model is not ZeroEntity zeroModel)
{
return model;
}
// set default properties
if (zeroModel.CreatedDate == default)
{
zeroModel.CreatedDate = DateTimeOffset.Now;
}
// update name alias and last modified
zeroModel.Alias = Safenames.Alias(zeroModel.Name);
zeroModel.LastModifiedDate = DateTimeOffset.Now;
zeroModel.Hash ??= IdGenerator.Create();
return model;
}
/// <inheritdoc />
public async Task<ValidationResult> Validate<T>(T model) where T : ZeroIdEntity, new()
{
IZeroMergedValidator<T> validator = Services.GetService<IZeroMergedValidator<T>>();
if (validator == null)
{
return new();
}
return await validator.ValidateAsync(model);
}
}
public interface IDbOperations
{
/// <summary>
/// Generate model Id by using configured document store conventions
/// </summary>
Task<string> GenerateId<T>(T model) where T : ZeroIdEntity;
/// <summary>
/// Generate values for all properties (incl. nested) which contain the [GenerateId] attribute
/// </summary>
T AutoSetIds<T>(T model);
/// <summary>
/// Automatically fill base properties of a ZeroEntity
/// </summary>
T PrepareForSave<T>(T model) where T : ZeroIdEntity;
}
+26
View File
@@ -0,0 +1,26 @@
using System;
using zero.Communication;
using zero.Configuration;
using zero.Context;
namespace zero.Sqlite;
public class StoreContext
{
public IZeroContext Context { get; private set; }
public IZeroOptions Options { get; private set; }
public IServiceProvider Services { get; private set; }
public IMessageAggregator Messages { get; private set; }
public StoreContext(IZeroContext context, IServiceProvider serviceProvider, IMessageAggregator messages)
{
Options = context.Options;
Context = context;
Services = serviceProvider;
Messages = messages;
}
}
+6
View File
@@ -0,0 +1,6 @@
namespace zero.Sqlite;
public class SqliteOptions
{
public string ConnectionString { get; set; }
}
+52
View File
@@ -0,0 +1,52 @@
using System;
using System.Data;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using ServiceStack.Data;
using ServiceStack.OrmLite;
using zero.Configuration;
using zero.Models;
using zero.Modules;
namespace zero.Sqlite;
public static class ZeroBuilderExtensions
{
public static ZeroBuilder AddSqlite(this ZeroBuilder builder)
{
builder.AddModule<ZeroSqliteModule>();
return builder;
}
}
internal class ZeroSqliteModule : ZeroModule
{
public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
services.AddSingleton<IDbConnectionFactory>(CreateDbConnectionFactory);
services.AddScoped<IDbConnection>(CreateDbConnection);
services.AddScoped<IDbOperations, DbOperations>();
services.AddScoped<StoreContext>();
services.AddOptions<FlavorOptions>();
services.AddOptions<SqliteOptions>().Bind(configuration.GetSection("Zero:Sqlite"));
services.ConfigureOptions<ConfigureFlavorJsonOptions>();
}
protected IDbConnectionFactory CreateDbConnectionFactory(IServiceProvider services)
{
IZeroOptions options = services.GetService<IZeroOptions>();
SqliteOptions ravenOptions = options.For<SqliteOptions>();
return new OrmLiteConnectionFactory(ravenOptions.ConnectionString, SqliteDialect.Provider);
}
protected IDbConnection CreateDbConnection(IServiceProvider services)
{
IDbConnectionFactory factory = services.GetService<IDbConnectionFactory>();
IDbConnection db = factory.CreateDbConnection();
db.Open();
//db.CreateTableIfNotExists<News>();
return db;
}
}
+21
View File
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageId>zero.Sqlite</PackageId>
<Version>1.0.0</Version>
<TargetFramework>net8.0</TargetFramework>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<RootNamespace>zero.Sqlite</RootNamespace>
<DebugType>embedded</DebugType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentValidation" Version="11.11.0" />
<PackageReference Include="ServiceStack.OrmLite.Sqlite" Version="8.8.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\zero\zero.csproj" />
</ItemGroup>
</Project>
+6
View File
@@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "zero", "zero\zero.csproj",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "zero.Raven", "zero.Raven\zero.Raven.csproj", "{DC79D7EA-FAA1-4701-9C36-8295CD1C45D0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "zero.Sqlite", "zero.Sqlite\zero.Sqlite.csproj", "{A57D88BC-952F-4311-B474-26FBF0FA957E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -21,6 +23,10 @@ Global
{DC79D7EA-FAA1-4701-9C36-8295CD1C45D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DC79D7EA-FAA1-4701-9C36-8295CD1C45D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DC79D7EA-FAA1-4701-9C36-8295CD1C45D0}.Release|Any CPU.Build.0 = Release|Any CPU
{A57D88BC-952F-4311-B474-26FBF0FA957E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A57D88BC-952F-4311-B474-26FBF0FA957E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A57D88BC-952F-4311-B474-26FBF0FA957E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A57D88BC-952F-4311-B474-26FBF0FA957E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE