Skip to content

Releases: redbase-app/redb

redb 3.7.2

Choose a tag to compare

@reliktbk reliktbk released this 27 Aug 11:23

redb 3.7.2

Ядро и провайдеры. Пакеты на nuget.org: redb.Core(.Pro), redb.Postgres(.Pro),
redb.MSSql(.Pro), redb.SQLite(.Pro), redb.Export, redb.CLI, redb.Templates, redb.Licensing.

Зачем этот выпуск. В 3.7.1 уехал регресс: array.Contains по nullable-массиву не
транслируется, а бросает исключение. Фильтр вида .Where(x => x.Tags.Contains(y))
перестаёт работать, как только Tags объявлен T[]? — а это то, что Nullable enable
даёт любому необязательному массиву. Виноват переход на .NET 10 в 3.7.1, а не
правка парсера: под net10 компилятор оборачивает коллекцию дважды.

3.7.1 остаётся в списке на nuget.org, образы остаются в реестре: небезопасного там
нет, версия вытеснена, а не отозвана.

Также в выпуске:

  • PVT-префильтр перестал отказывать в трёх шаблонах запросов, где отказ был лишним:
    вложенный OR под AND, несколько ветвей по одной структуре, ListItem.Id.
  • Найденный при этом дефект слияния ветвей: группировка шла по одной структуре, из-за
    чего строковый шаблон мог склеиться с bigint-колонкой.
  • Планировщик префильтра объясняет себя в ToSqlStringAsync — девять кодов причин отказа.

Проверено на .NET 10.0.8, набор целится в net10.0: 1942 из 1944, два штатных Skip,
прогон дважды — с включённым и выключенным префильтром. Шесть провайдерских коллекций
плюс модульные: 1920 из 1920 в обоих режимах.

Установка:
dotnet add package redb.Core
dotnet add package redb.Postgres.Pro # Pro бесплатен на всей линии 3.x, ключ не нужен

redb 3.7.1

Choose a tag to compare

@reliktbk reliktbk released this 26 Aug 13:37

redb 3.7.1

Ядро и провайдеры. Пакеты на nuget.org: redb.Core(.Pro), redb.Postgres(.Pro),
redb.MSSql(.Pro), redb.SQLite(.Pro), redb.Export, redb.CLI, redb.Templates, redb.Licensing.

3.7.0 ОТОЗВАН. Он собран на .NET 9 и несёт известные уязвимости в зависимостях; все
пакеты 3.7.0 разлистованы на nuget.org. Разлистованная версия остаётся устанавливаемой
по точному номеру, но ставить её не нужно — 3.7.1 заменяет её полностью.

Безопасность:

  • redb.Export тянул уязвимый SQLitePCLRaw.lib.e_sqlite3 2.1.10 транзитивно через
    Microsoft.Data.Sqlite 9.0.3 (GHSA-2m69-gcr7-jv3q, высокий уровень). В redb.SQLite эта
    дыра была закрыта пином давно, redb.Export прошёл мимо защиты. Пакет поднят до 10.0.0
    плюс явный пин lib.e_sqlite3 3.50.3.

Сборка:

  • Библиотеки по-прежнему мультитаргетятся net8.0;net9.0;net10.0 — ничего не сломано.
  • redb.CLI переведён на net10.0 и ТЕПЕРЬ ТРЕБУЕТ .NET 10 на машине. Раньше он собирался
    под net8.0 и вставал на любой рантайм .NET 8 и новее; роллфорвард работает только вверх,
    поэтому на машине с одним лишь .NET 8 или .NET 9 тул больше не установится.
    .NET 8 и .NET 9 уходят из поддержки Microsoft 10 ноября 2026, .NET 10 — до 14 ноября 2028.

Установка:
dotnet add package redb.Core
dotnet add package redb.Postgres.Pro # Pro бесплатен на всей линии 3.x, ключ не нужен

redb 3.6.0

Choose a tag to compare

@reliktbk reliktbk released this 19 Aug 19:29

redb 3.6.0

Ядро и провайдеры. Пакеты на nuget.org: redb.Core(.Pro), redb.Postgres(.Pro),
redb.MSSql(.Pro), redb.SQLite(.Pro), redb.Export, redb.CLI, redb.Templates, redb.Licensing.

Исправления этого выпуска:

  • TreeQuery(root).WhereLeaves()/.WhereRoots() игнорировали корень и сканировали всю схему —
    запрос молча возвращал узлы соседних деревьев. Починено на всех шести комбинациях
    провайдер x Free/Pro, включая нативное расширение SQLite (redb_pvt.c).
  • SumRedbAsync/AverageRedbAsync бросали InvalidOperationException на пустой выборке.
  • Хеширование падало на Blazor WebAssembly (в браузере нет MD5-провайдера) — добавлена
    управляемая реализация RFC 1321, побитово совпадающая с System.Security.Cryptography.MD5.
  • Props-кэш мог отдать объект, изменённый на месте после кэширования.
  • RedbHash зависел от порядка ключей в Dictionary.
  • Android-приложения тащили ~360 КБ неработающих Linux-бинарей: нативное расширение Free-тира
    переехало из runtimes//native/ в buildTransitive/native//. Раскладка в выходном
    каталоге потребителя не изменилась.

Установка:
dotnet add package redb.Core
dotnet add package redb.Postgres.Pro # Pro бесплатен на всей линии 3.x, ключ не нужен

v3.4.0

Choose a tag to compare

@reliktbk reliktbk released this 27 Jul 19:53

Why 3.4.0 (a minor bump), not 3.3.4. This release adds features, not just fixes: explicit scheme
names ([RedbScheme(Name = "...")]), scheme-name validation triggers on MSSql/SQLite, and the new
ThrowOnSchemeMismatch load-time guard. Under SemVer that is a minor version. The core packages
(RedBase.Core, the three providers Free/Pro, RedBase.Export, RedBase.CLI) move together to
3.4.0; redb.Route, redb.Tsak and redb.Identity keep their own version lines.

Added

  • Explicit scheme names — [RedbScheme(Name = "...")] (RedBase.Core + all providers). Until now
    a scheme was always named after the CLR type's FullName, and the string in the attribute was only
    a cosmetic _alias. A scheme name can now be pinned explicitly, which decouples the database
    identity of a scheme from C# namespace/class refactoring.

    The positional argument is, and stays, the alias — an explicit name is only settable through the
    named Name parameter, so not one existing declaration changes meaning. Types that declare no
    Name behave exactly as before.

    On the first sync a type with an explicit name has its scheme renamed in the database. The
    scheme is looked up along a three-step chain — explicit name, FullName, short type name — and the
    first match is renamed in place. The rename is a single-row UPDATE of _schemes._name: the id is
    preserved, so objects, structures and values are untouched, and polymorphic loading (which resolves
    through scheme_id) is unaffected.

    Renaming requires every consumer of that database to be updated together. An application
    version that predates the explicit name will not find the scheme under its new name and will
    create a second one, splitting objects between them silently. If that has already happened, redb
    now detects it and refuses to continue rather than picking one of the two.

    Explicit names must follow C# identifier rules (Latin letters, digits, _, ., +; no reserved
    words; 128 characters max) and are validated in C# before any SQL is issued, so the error names the
    offending type. Human-readable titles belong in Alias, which is free-form.

  • Scheme-name validation in MSSql and SQLite (RedBase.MSSql, RedBase.SQLite). Both providers
    now carry a _schemes name-validation trigger mirroring the PostgreSQL validate_scheme_name()
    rule for rule, so a name accepted by one provider is accepted by all three. Applies to
    newly created databases onlyEnsureDatabaseAsync skips initialisation when _schemes
    already exists. The C#-level validation covers databases of any age.

  • RedbServiceConfiguration.ThrowOnSchemeMismatch (RedBase.Core, default false). Chooses how
    LoadAsync<TProps> reacts when the object's scheme does not match TProps (see Fixed): false
    returns null (so a soft-deleted object, scheme -10, reads as null — what soft-delete callers
    expect); true throws RedbSchemeMismatchException to surface a genuine type mistake loudly.

Changed

  • The SQLite native extension is renamed redbredbsqlite (RedBase.SQLite, Free tier).
    The package now ships runtimes/<rid>/native/redbsqlite.{dll,so} (win-x64, linux-x64, linux-arm64)
    instead of redb.{dll,so}. The generic name collided with the managed redb.* assemblies and with
    the redb.* prune globs a host applies to its own bin directory — a native loadable module was
    being swept up as if it were one of ours. The C init symbol is unchanged (sqlite3_redb_init)
    and the binaries are byte-for-byte the ones shipped as redb.* in 3.3.3: this is a rename of the
    file, not a rebuild, and LoadExtension has always been called with an explicit entry point.
    • Nothing to do if you let the package resolve the extension (SqliteDataSource .LocatePackagedExtension(), the default for the Free DI registration) — it looks for the new name.
    • Action required if you pin the path yourself — REDB_SQLITE_EXTENSION, an explicit
      NativeExtensionPath, a Dockerfile COPY, or a deploy script that copies redb.so by name:
      point it at redbsqlite.{dll,so}. A stale path fails at connection open, not at build.

Fixed

  • Concurrent start-up of several nodes could fail to create a scheme (RedBase.Core + all
    providers).
    Reproduced in production on a three-node cluster. When several instances started
    against a database that did not yet have a given scheme, all of them missed the lookup and all
    issued INSERT INTO _schemes; every instance but one failed with an unhandled UNIQUE(_name)
    violation during initialisation.

    Scheme creation now uses a conflict-free statement per dialect (ON CONFLICT (_name) DO NOTHING on
    PostgreSQL and SQLite, INSERT ... WHERE NOT EXISTS with UPDLOCK, HOLDLOCK on MSSql) and the
    instance that loses the race reads back the winner's row. Catching the violation instead would not
    have worked: on PostgreSQL a failed statement inside a transaction poisons it, so the follow-up
    read would fail with 25P02. Both creation paths are covered — typed
    (EnsureSchemeFromTypeAsync<T>) and untyped (EnsureObjectSchemeAsync).

  • Pro data migrations never ran — on any provider (RedBase.Core.Pro, RedBase.SQLite,
    RedBase.MSSql).
    Four separate defects stacked on top of each other, and the feature had no test
    coverage at all, so none of them had ever surfaced:

    1. MigrationExtensions.CreateExecutor fetched the DB context by reflection asking for a
      NonPublic Context property, but RedbServiceBase.Context is public — the lookup never
      matched and every migration died with "Cannot get IRedbContext from RedbService". It now uses
      redb.Context and (ISchemeSyncProvider)redb directly; both are part of IRedbService.
    2. The generated UPDATE was hardcoded to PostgreSQL syntax (UPDATE _values target ...). SQLite
      forbids aliasing an UPDATE target (near "target": syntax error) and T-SQL needs the alias
      bound in a trailing FROM. Added ISqlDialectPro.Migration_UpdateTarget(table, alias) with
      one implementation per provider.
    3. SQLite had no _migrations history table at all: PG/MSSql get it from the concatenated
      redb_init.sql, and SQLite has no such concatenation step, so the shared redb_migrations.sql
      never reached it. A SQLite-native DDL (INTEGER PK, REAL Julian _applied_at, INTEGER
      _dry_run) now ships in redbSqlite.sql.
    4. MSSql declared _migrations._id as IDENTITY(1,1) — the only IDENTITY in the whole MSSql
      schema — while the executor supplies ids explicitly like every other redb table, so writing
      history failed with "Cannot insert explicit value for identity column". IDENTITY removed.

    Covered by a new MigrationTestsBase suite (apply / history row / idempotency / dry-run) running
    against all three Pro fixtures. Note: existing databases do not receive the corrected _migrations
    DDL, since EnsureDatabaseAsync skips initialisation when _schemes already exists — but no
    database can hold real migration history, because the feature could not complete a single run.

  • A scheme's _alias was never updated after creation (RedBase.Core + all providers). It was
    written once on INSERT and then frozen: changing [RedbScheme("...")] on a class left the old
    value in the database forever. Structure aliases have always synchronised (Structures_UpdateAlias);
    schemes simply had no equivalent. They do now — the attribute is the source of truth, removing it
    resets _alias to NULL, and a value edited by hand in the database is overwritten on the next sync.

  • ClrSchemeTypeIndex pinned hot-reloaded plugin modules in memory (RedBase.Core). The
    process-global schemeName → Type index held strong Type references, and a Type keeps its
    AssemblyLoadContext alive — so a collectible ALC (Tsak hot-swap) could never be collected, and after
    a reload the stale instance produced a false RedbSchemeNameConflictException against the fresh one,
    blocking the module from loading. Entries are now WeakReference<Type> (dead ones pruned on lookup),
    and two instances of the same FullName from different ALCs are recognised as a reload, not a name
    clash. Distinct types sharing one explicit Name still conflict, by design.

  • LoadAsync<TProps> did not verify the loaded object's scheme (RedBase.Core + all providers).
    Loading an object of one scheme under an unrelated TProps deserialised garbage into the Props and —
    with EnablePropsCache — cached it under objectId, so a later GetWithoutHashValidation kept
    returning the garbage. LoadAsync<TProps> now checks the object's _id_scheme against the scheme
    TProps maps to before anything is cached. By default a mismatch returns null — so a soft-deleted
    object (scheme -10, set by SoftDeleteAsync) reads as null, which is what soft-delete callers
    expect; set RedbServiceConfiguration.ThrowOnSchemeMismatch = true to instead throw
    RedbSchemeMismatchException on a genuine type mistake. Either way garbage never reaches the cache.
    The untyped LoadAsync(objectId) is never affected.

  • Invalid explicit scheme names failed one at a time (RedBase.Core). Auto-sync validates every
    [RedbScheme(Name = "...")] and (by design) refuses to boot on an invalid name — but it stopped at
    the first offender, so a codebase with several had to be fixed one rerun at a time. Names are now all
    validated up front and reported together in a single AggregateException.

Removed

  • Dead metadata-cache interface layer (RedBase.Core). ICompositeMetadataCache,
    ISchemeMetadataCache, IStructureMetadataCache, ITypeMetadataCache, IStaticMetadataCache and
    StaticMetadataCache — 679 lines across five files that referenced only each other. None was ever
    implemented, none was ever consumed; the live cache...
Read more

v3.3.3

Choose a tag to compare

@reliktbk reliktbk released this 16 Jul 15:36

Why 3.3.3 and not 3.3.1. The number jumps to stay in step with the rest of the ecosystem, which
had drifted ahead: redb.Route and redb.Tsak were at 3.3.1, and redb.Route.Sql / redb.Route.Sqs
at 3.3.2 (a partial connector release). From 3.3.3 every package ships one number — redb core,
redb.Route and redb.Tsak — so "which versions go together" stops being a question. There are no core
releases numbered 3.3.1 or 3.3.2; the fix below is the only functional change here.

redb.Identity keeps its own line (1.2.2) but is released together with this — it depends on redb
storage, and without the rebuild its users would stay on the broken init below.

Fixed

  • Schema init failed under a non-superuser database owner (RedBase.Postgres). The embedded
    redb_init.sql carried a single ALTER FUNCTION migrate_structure_type(...) OWNER TO postgres;
    (a leftover from a debugging session — the only OWNER TO in the whole script). EnsureCreated=true runs
    the script as one batch, so on a least-privilege setup (app user owns the database but is not a
    member of the postgres role) the statement failed with "must be able to SET ROLE postgres"
    and rolled back the entire first-start initialization. The statement is removed: no function in
    the script is SECURITY DEFINER, so ownership never affected execution, and the function now
    belongs to the connecting role like every other object — which also keeps future
    CREATE OR REPLACE migrations working. Required app privileges are now just
    CONNECT + CREATE on the schema + DML. Note: CREATE EXTENSION IF NOT EXISTS pg_trgm still
    requires the extension to be preinstalled on PostgreSQL ≤ 12 (on PG 13+ pg_trgm is a trusted
    extension, installable by the database owner).

v3.3.0

Choose a tag to compare

@reliktbk reliktbk released this 08 Jul 22:08

Added

  • Fail-fast concurrency guard on the provider connection (RedBase.Postgres, RedBase.MSSql,
    RedBase.SQLite + .Pro).
    An IRedbService wraps a single, non-thread-safe DB connection
    (EF-DbContext model). If the same instance is entered from two threads at once, each provider now
    throws a clear InvalidOperationException naming the cause — instead of an opaque driver error
    ("A command is already in progress", "connection is busy", "another read operation is already
    in progress"
    ). Lightweight Interlocked check with zero cost on the normal single-threaded path;
    correct scoped usage is never affected.

Fixed

  • Query parser: array.Contains(x) in WhereRedb threw on .NET 9 / C# 13 (RedBase.Core).
    A string[] (or any array) .Contains(x) inside a WhereRedb(...) predicate now binds to the
    ReadOnlySpan overload (System.MemoryExtensions.Contains) rather than Enumerable.Contains,
    which the filter parser rejected with NotSupportedException. The parser now recognises
    MemoryExtensions.Contains, unwraps the array→span conversion, and translates it to the same
    IN clause as Enumerable.Contains / List.Contains. (Refactored the two-arg Contains
    translation into a shared VisitContainsCore.)
  • ComputeHash() NRE on an object with Props == null (RedBase.Core). RedbHash.ComputeForObject
    dereferenced the object before a null check, so the generic ComputeFor<TProps> path (used by
    RedbObject<TProps>.ComputeHash()) threw NullReferenceException when Props was null — even
    though null Props is a supported case (the reflection-based ComputeFor(IRedbObject) already
    returned null, and ComputeForBaseFields exists for exactly this). Added the missing guard so the
    generic path returns null (→ Guid.Empty) consistently, instead of throwing.
  • Connection-pool leak on transaction/connection dispose (RedBase.Postgres, RedBase.MSSql,
    RedBase.SQLite + .Pro).
    Disposing the provider connection could skip returning the physical
    connection to the pool: a throw from the driver's transaction DisposeAsync() (possible mid
    error-storm on an already-broken connection) bypassed _connection disposal. Because SaveAsync
    runs inside an explicit transaction, every write armed this path, so under a burst of failures the
    leak was self-amplifying and eventually exhausted the pool (symptom: a healthy pool suddenly climbs
    past MaxPoolSize with connection-timeout errors, cleared only by a restart). The connection's
    DisposeAsync/Dispose and the transaction wrapper's DisposeAsync now use try/finally, so the
    connection is always returned and the transaction-cleanup callback always runs; the dispose fault is
    no longer swallowed — it propagates so it stays observable.

v3.2.0

Choose a tag to compare

@reliktbk reliktbk released this 29 Jun 21:10

RedBase 3.2.0 - see CHANGELOG.md. NuGet: https://www.nuget.org/profiles/relikt

v3.0.0

Choose a tag to compare

@reliktbk reliktbk released this 29 May 23:53

Added

  • PG Free: full v2-pvt query engine reaches Pro-parity (0.5.x → 0.6.1).
    The PostgreSQL Free path got the feature-complete v2-pvt module ahead of
    MSSql Free (commits 2026-05-21 … 2026-05-28). Before this series the Free
    path was emitting -- not available in Open Source stubs for several
    preview surfaces and was missing several Pro-only operators. Now in Free
    on PG:

    • Universal "no black box" SQL preview for GroupBy / Window /
      GroupedWindow / Tree-* via two-pass compile (pvt_build_*_sql);
      tree previews resolve the subtree and delegate to the matching non-tree
      preview with a -- Tree …: subtree resolved to N object(s) header.
    • Sql.Function<T> whitelist at the SQL boundary
      (17_pvt_expr.sql) with a
      hardcoded ELSIF chain and RAISE EXCEPTION for non-whitelisted names;
      parser routes Sql.Function<T>(name, args) to
      CustomFunctionExpression (FREE-OVER-PRO §2.4).
    • ValueTuple composite dict keys (Dictionary<(int,int), V>)
      consistently encoded as Base64-JSON on both write and read sides
      (FREE-OVER-PRO §2.2).
    • arr.Length / coll.Count in filters via the array-aware
      FacetFilterBuilder (.$count modifier in Free); e.Tags.Any()
      1-arg form mapped to <field>.$length > 0.
    • Take(0) returns empty instead of ArgumentException.
    • HAVING parser + ArrayGroupBy with PVT agg array unnest
      (19_pvt_agg_expr.sql) —
      fixes 42883 function sum(bigint[]) does not exist;
      26_pvt_array_groupby.sql
      added.
    • ListItem.Value / .Alias via a single LEFT JOIN _list_items
      (v2-pvt 0.6.1) — plan-shape parity with Pro; replaces correlated
      subquery per field.
    • Nested-dict CTE pushdown for Field[key].Child (FREE-OVER-PRO §2.x):
      outer WHERE references the already-built pivot column instead of a
      redundant EXISTS over _values.
    • Auto-deploy of the v2-pvt bundle on version mismatch (see the
      matching item below — same infrastructure serves both PG and MSSql).

    The MSSql Free engine described next ports this PG Free baseline; the
    parity line in the next item ("145/145 parity with PG Free") refers to
    this newly-completed PG Free feature set, not a pre-existing one.

  • MSSql Free: full v2-pvt query engine (0.1.0 → 0.1.3) — 145/145 parity
    with PG Free
    . The old MSSql Free path generated a wide inline CASE WHEN
    aggregate; it is now replaced with the Pro-shape CTE: a single pass over
    _values using MAX(CASE WHEN _id_structure = X AND _array_index IS NULL THEN ...) and a single LEFT JOIN _list_items. All modes present in PG
    Free are implemented: flat/tree, scalar/array/dict fields, ListItem
    (.Id/.Value/.Alias), same-scheme nested POCO (compound path),
    OrderBy/DistinctBy/Take/Skip, GroupBy/HAVING, ArrayGroupBy
    (via OUTER APPLY), array aggregates ($count, $sum/$avg/$min/$max
    over _Long/_Double/_Numeric/_DateTimeOffset), array operators
    ($arrayContains, $arrayAny, $arrayCount*, $arrayAt,
    $arrayStartsWith, etc.), Sql.Function (whitelist), $expr, null
    semantics ($exists/$notNull). The SQL module is split into 27 source
    files under redb.MSSql/sql/v2-pvt/ assembled
    into a single pvt_bundle.sql by MSBuild. Delivery stages: Stage 1 (pivot
    CTE) → 2a (tree TVFs) → 2b (tree provider) → 2c.E (nested-dict accessor
    Field[key].Child) → 0.1.1 LIKE-pattern fix → 0.1.2 string $const
    unwrap + ListItem $arrayContains → 0.1.3 nested-dict CTE pushdown +
    outer WHERE references pivot column instead of a redundant EXISTS.
    Shape parity with Pro throughout: _id_scheme + extra_where +
    tree-filter pushed into inner _objects subquery, narrow-with-nested CTE
    (skips _values JOIN when no scalar sids), stable default ORDER BY when
    paging without an explicit order.

  • Auto-deploy v2-pvt bundle on version mismatch (both databases).
    ISqlDialect gained Query_PvtRequiredVersion() — the semver the embedded
    bundle ships. RedbServiceBase.EnsurePvtModuleDeployedAsync reads
    pvt_module_version() on InitializeAsync(), compares with an exact-match,
    and automatically applies the embedded pvt_bundle.sql resource when the
    deployed version differs. No more manual DROP FUNCTION … CREATE FUNCTION …
    after a SQL change. The MSBuild target ConcatenateSqlFiles regenerates the
    bundle whenever any .sql source changes (hooked to DispatchToInnerBuilds
    for multi-TFM builds; EmbeddedResource uses an explicit LogicalName
    without it MSBuild silently replaces - with _ in resource paths, causing
    GetManifestResourceStream to return null).

  • Pro: GroupBy + HAVING via PVT pipeline on both providers
    (Postgres.Pro + MSSql.Pro)
    . HavingAsync existed in Free but had no Pro
    counterpart. Added full HAVING parser in the shared facet layer
    (FacetFilterBuilder), SQL generation in both Pro providers, and a base
    test suite in
    GroupByHavingTestsBase
    with per-dialect wrappers (PG, PG.Pro, MSSql.Pro). 33/33 HAVING + 6/6
    no-HAVING — all green.

  • Pro: GroupBy over array fields (ArrayGroupBy) — unified implementation
    for Postgres.Pro + MSSql.Pro
    . PG.Pro uses an inline GroupByArray override
    with PVT agg array unnest; MSSql.Pro has its own override.
    GroupBy(items => items.SelectMany(o => o.Skills)) with aggregates works
    on all four tiers (PG Free, PG.Pro, MSSql Free, MSSql.Pro).

  • MSSql Pro: AggregateBatch parity with PG.Pro — non-numeric MIN/MAX and
    inline filter subquery
    . MinAsync/MaxAsync over string/DateTime/Guid
    fields and a Where filter inside a batch aggregation now produce the same
    query shape as PG.Pro (PVT CTE + outer aggregate).

  • MSSql Free: pushdown parity with Pro/PG for expression-form predicates
    and $expr
    — the filter-splitting optimizer
    pvt_split_filter now pushes
    top-level $eq/$ne/$lt/$lte/$gt/$gte/$like/$ilike/$in/$nin/$between/$null/ $notnull/$contains/$startsWith/$endsWith expressions and arbitrary boolean
    $expr trees into the inner _objects o subquery (Shape A) when all
    $field references resolve to kind='base'. If any props field is present
    the node stays in the residual (Shape C). The new classifier
    pvt_expr_is_base_only makes
    this decision; the pushdown SQL itself is generated by the existing
    pvt_build_where_from_json
    walker (extended with a $expr branch). Covered by 4 functional and 3
    shape-inspect tests in
    99_smoke_auto.sql
    (195 PASS / 0 FAIL / 1 SKIP).

Fixed

  • Schema sync now honors Configuration.DefaultStrictDeleteExtra
    (FREE-OVER-PRO §4 #1). Prior to this fix RedbServiceConfiguration.DefaultStrictDeleteExtra
    was set by builders, copied across configuration clones and read from
    appsettings, but no execution-path code consumed it
    SchemeSyncProviderBase.SyncSchemeAsync<T>
    hardcoded strictDeleteExtra: true, so old binaries restarting in a
    multi-version rolling deploy would unconditionally remove _structures
    rows added by the new binary, and every _values row referencing those
    structures along with them. On PostgreSQL this is done via the FK
    _values._id_structure -> _structures._id ON DELETE CASCADE
    (redbPostgre.sql:215). On MSSQL
    the same effect is produced by the INSTEAD OF DELETE trigger
    TR__structures__cascade_values
    (redbMSSQL.sql:717) — the FK
    NO ACTION at redbMSSQL.sql:270
    is a workaround for the MSSQL multiple-cascade-paths restriction, not a
    behavioral difference. SyncSchemeAsync<T> now reads
    now reads Configuration.DefaultStrictDeleteExtra instead. The default
    value is preserved (true) so users on the default config see no
    behavioral change. Behavioral change: the built-in presets
    Development, HighPerformance, and Migration (in
    PredefinedConfigurations.cs)
    already declared DefaultStrictDeleteExtra = false; that setting was
    silently ignored before and now actually takes effect — apps on those
    presets will no longer auto-delete _structures rows missing from the
    Props class on startup.

Added
a fallback to ROW_NUMBER() OVER (PARTITION BY <key> ORDER BY (SELECT 1))

  • WHERE _rn = 1 (symmetric with the Free path), plus support for
    CoalesceExpression in the DistinctBy key.
  • PG v2-pvt 0.6.1: ListItem .Value/.Alias now uses a single
    LEFT JOIN _list_items
    instead of a correlated subquery per field —
    plan-shape parity with Pro. Additionally: nested-dict predicates in the
    outer WHERE now reference _pvt_cte.[<field>] (the already-built pivot
    column) instead of re-running a separate EXISTS over _values.

  • MSSql Free: ORDER BY $expr on base fields no longer produces "constant
    in ORDER BY"
    — two regressions fixed: (1)
    pvt_collect_fields
    did not walk $expr nodes in order entries, so a field like Age was not
    collected, the shape was classified as A, and pvt_b2_expr_sql emitted
    /*unknown-b2-field:Age*/NULL turning Age*2 into a constant; (2)
    [pvt_build_order_conditions](redb.MSSql/sql/v2-pvt...

Read more

v2.0.2

Choose a tag to compare

@reliktbk reliktbk released this 16 May 10:19

RedBase 2.0.2. See CHANGELOG.md for details. NuGet: https://www.nuget.org/profiles/relikt

v2.0.1

Choose a tag to compare

@reliktbk reliktbk released this 08 May 21:10

RedBase 2.0.1 — Pro EAV LINQ→SQL fix. License migrated MIT → Apache-2.0 for all OSS packages. Strong-name signing active for Pro assemblies. See CHANGELOG.md for details. NuGet: https://www.nuget.org/profiles/relikt