Skip to content

Wire the model builder to the field type registry - #2733

Merged
pournasserian merged 1 commit into
mainfrom
feat/2730-model-builder-registry-19ef70
Nov 2, 2026
Merged

pournasserian merged 1 commit into
mainfrom
feat/2730-model-builder-registry-19ef70

Conversation

@pournasserian

Copy link
Copy Markdown
Member

Closes #2730

What

FieldStorage now asks the field type registry the schema was built with where a field lives (IFieldType.StorageKind) and keeps only the column CLR type and length defaults of the core types. The three schema checks that ContentModelBuilder raised at the first context.Model access (and the duplicate-column check) now run in SchemaValidator, so they appear at SchemaBuilder.Build() with the other FCMS12xx errors. ContentModelBuilder no longer references SchemaValidationException or SchemaError.

Why

A plugin field type the validator accepted used to throw InvalidOperationException when the context built its model, and a field named siteId only failed on the first query.

Dependencies

None. No new packages or actions.

Decisions beyond the issue

  • Registry on the schema. SchemaModel gets an internal IFieldTypeRegistry FieldTypes, set by SchemaBuilder.Build() through the internal constructor. It adds nothing to PublicAPI.Unshipped.txt, stays out of SchemaJsonWriter and SchemaModelKey, and the model builder needs no second reference. I rejected a public property (surface to keep after 1.0) and a side table keyed by SchemaModel (hidden state). A SchemaModel built any other way would have no registry, but the constructor is internal and only SchemaBuilder calls it.
  • Plugin Column type is a nullable string. It honours [Length] max, is never NOT NULL, has no default. A plugin that needs another CLR type stores a string form. A plugin Json type is a nullable JSON string column; if the field is Multiple it is NOT NULL DEFAULT '[]', as the core lists are.
  • Storage kind overrides the field name. Core select and component with Multiple are Json because their StorageKind says so. A single component is still flattened by name, since it is the only type whose columns come from another type.
  • FCMS1202 moves too. The issue names 1206 and 1211, but its acceptance says the builder raises no SchemaValidationException, and two fields on one column was the third such check.
  • System table reservations are static (interpretation). Every table of spec Appendix C is reserved, first-party plugin tables included, so a type called job fails now rather than after Database-backed job runner with leases, retries, dead letter and recurring jobs #2698 adds cms_job. The {type}-i18n beside a localized type check stays. The list lives in StorageNames.SystemTables, built from StorageNames.Prefix and the existing Document, Reference and Version constants; system columns (SystemColumns, LocaleTableColumns) live there too and StorageNames.Table/LocaleTable take a type name so the validator and the mapping share them. Only collections and singletons are checked; a component or block named job has no table. A new Appendix C table must be added to that list.
  • Error text for a taken table changed from "already taken" to "which a system table already uses" or "which is the locale table of ...", since it can no longer see mapped entities.
  • No double report. A top-level field named like a system field (id, locale) is already FCMS1206 by name, so the column check does not report it a second time. A repeated field name is reported once, as before.
  • Storage checks run after the other checks, on drafts. SchemaModelFactory.Create(FieldDraft) became internal-visible so the validator can ask the registry about a draft.

Acceptance

  • A plugin field type with storage kind Column builds a context and round-trips a row on SQLite without a change to FieldStorage (PluginFieldStorageTests; Json as well)
  • A field named siteId and a collection named version fail SchemaBuilder.Build() with FCMS1206 (also job and the other Appendix C tables)
  • ContentModelBuilder raises no SchemaValidationException of its own (ContentModelBuilderRaisesNoSchemaErrorsOfItsOwn inspects the source)
  • Existing storage and schema tests pass unchanged except for the moved error source (the five storage-error tests moved from ContentModelTests to StorageSchemaValidationTests and now call Build(); the FieldStorage test of an unmapped field type now asserts the plugin mapping)

Verified on SQLite only (Q19): dotnet build -c Release -warnaserror and dotnet test -c Release pass.

@pournasserian
pournasserian merged commit 7890c4f into main Nov 2, 2026
5 checks passed
@pournasserian
pournasserian deleted the feat/2730-model-builder-registry-19ef70 branch November 2, 2026 15:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Wire the model builder to the field type registry and move its schema checks into the validator

1 participant