Overview

After #3468269: `ComponentTreeStructure` data type: simplify the stored structure lands, there's another thing that @longwave pointed out (that I happened to have thought overnight too 😇): why use a JSON blob at all for the tree prop aka the ComponentTreeStructure data type?

Or, does this really need to be JSON at all? Can we just have a flat table?

parent,slot,delta,uuid,component
ROOT_UUID,root,0,uuid-root-1,provider:two-col
ROOT_UUID,root,1,uuid-root-2,provider:marquee
ROOT_UUID,root,2,uuid-root-3,provider:marquee
uuid-root-1,firstColumn,0,uuid4-author1,provider:person-card
uuid-root-1,firstColumn,1,uuid2-submitted,provider:elegant-date
uuid-root-1,secondColumn,0,uuid5-author2,provider:person-card
uuid-root-2,content,0,uuid-author3,provider:person-card

https://git.drupalcode.org/project/experience_builder/-/merge_requests/1...

Proposed resolution

Spike objectives:

  1. Determine if this is feasible
  2. Consider the implications for API consumers like JSON:API
  3. Find out any possible downsides
  4. Size the remaining work that would be required to implement this

User interface changes

None.

CommentFileSizeAuthor
#43 Screenshot 2025-05-22 at 7.31.01 PM.png202.43 KBwim leers
Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

Wim Leers created an issue. See original summary.

lauriii’s picture

Would it be possible to document what are the benefits and downsides of using a flat table over a JSON blob? Based on the issue summary, it isn't clear to me what are the trade-offs involved in this decision.

wim leers’s picture

Assigned: Unassigned » effulgentsia
Status: Postponed » Active
Related issues:

Thoughts:

  • I agree a JSON blob is overkill and a table is in principle sufficient.
  • … but Drupal's Entity Field system assumes every field prop corresponds to a data type (true here too), and that data type must be a single column in the database (not true here), and is always a primitive (the data type class must implement \Drupal\Core\TypedData\PrimitiveInterface if that data type is used for a field property — AFAICT)
  • So then IMHO the question becomes: how do we store such a table in a single DB column?

The only exception I can think of (right now, in the little time I have this morning while writing this up to ensure we follow through!): the PathItem field type, which essentially is a computed field type that stores its data in another database table and does the necessary additional DB queries.

Maybe that can work? That maybe actually gets closer to @effulgentsia's original proposal at #3440578: [PP-2] JSON-based data storage proposal for component-based page building, where he proposed to do some deduplication stuff that most of us wanted to defer to later?

We could then literally have a single DB table for all XB uses, by expanding the columns from

parent,slot,delta,uuid,component

(@longwave's comment)
to:

entity_type_id,entity_id,field_name,parent,slot,delta,uuid,component

… which would not violate the 3.2.4 Facilitating `component props` changes section in docs/data-model.md.

longwave’s picture

One benefit is this becomes trivial:

An upgrade path for a `component` would require logic somewhat like this:

1. SQL query to search the _tree_ JSON blob for uses of this `component`, capture the UUIDs.

SELECT uuid FROM table WHERE component = "provider:person-card"

@Wim Leers additional note: we also have to consider langcode for asymmetric translations

catch’s picture

@lauriii One of the advantages here is it would (at least partially) solve the same problem of non-portable JSON queries (which are already in the XB code base) that #3457504: XB field type: calculate all dependencies, store them, surface in new Component "Audit" operation is also trying to remove - same general problem as #5.

catch’s picture

… but Drupal's Entity Field system assumes every field prop corresponds to a data type (true here too), and that data type must be a single column in the database (not true here), and is always a primitive (the data type class must implement \Drupal\Core\TypedData\PrimitiveInterface if that data type is used for a field property — AFAICT)

I'm not sure exactly which data isn't fitting in a single column, but could only that column be JSON (storing a flat array of whatever doesn't fit) without undermining the goal of the issue?

wim leers’s picture

#5++

#6++

#7: an XB field must store a tree of components + sources for their props values. This issue proposes to store that tree as a list, so not as a single column in a single row, but as multiple columns in multiple rows. That's what I was trying to convey in #4, and is also why I pointed to @effulgentsia's "deduplication" proposal (we could implement this by storing a single value for each XB field revision's tree, with that value pointing to a foreign key in another table, where @longwave's proposed columns could then be used).

effulgentsia’s picture

Assigned: effulgentsia » Unassigned

I think this proposal makes sense. My initial thinking behind JSON for this was thinking we wanted to store it as a tree. But since we've already changed that to a flat JSON representation, I don't think JSON for this part has any special value.

Drupal's Entity Field system assumes every field prop corresponds to a ... single column in the database

I think what we could do is store this as a multi-valued field. If we want to keep tree and props as a single field, we could do that by each item containing the following properties/columns: component_instance_id, component, parent, slot, delta_in_slot, props, where that last one is the JSON props source/expression/values for that component instance.

However, at some point, I think it will make sense for us to model this as two fields: in other words, pull the props column out of the above suggestion and make it its own separate field from the field representing the tree. Not sure if we want to jump to the two field implementation as part of this issue or continue to keep it as one field until we separately discuss the pros and cons of two fields vs one.

johnwebdev’s picture

#4

We could then literally have a single DB table for all XB uses, by expanding the columns from

entity_type_id,entity_id,field_name,parent,slot,delta,uuid,component

I'm not sure that would work with revisions and sync/async translations?

quietone’s picture

Related issues:

Removed duplicate related item.

larowlan’s picture

Title: [PP-1] Consider not storing the ComponentTreeStructure data type as a JSON blob » Spike: Explore storing the ComponentTreeStructure data type one row per component
Status: Closed (duplicate) » Active
Parent issue: » #3477428: [PP-1] Refactor (or decide not to) the XB field type to be multi-valued, to de-jsonify the tree, and to reference the field_union type of the prop values
Related issues: +#3523842: Spike: Explore storing a hash lookup of the ComponentInputs field property: one hash per component instance

Repurposing this as a spike to explore storing the tree in a flat structure and unblocking #3523842: Spike: Explore storing a hash lookup of the ComponentInputs field property: one hash per component instance which would basically be the proposal in comment #9 here, but instead of props we'd store the lookup hash

Additionally there's scope to use CTEs here like we do in Entity hierarchy v5 to retrieve an ordered tree in a single SQL query should we need it. That module has views integration to let people do things like 'is child of' and 'is parent of' in a single query - which might be attractive for issues like #3462219: [META] Support alternative renderings of prop data added for the 'full' view mode such as for search indexing or newsletters

larowlan’s picture

Issue summary: View changes
larowlan’s picture

Issue summary: View changes
larowlan’s picture

Assigned: Unassigned » larowlan

Picking this spike up

wim leers’s picture

👏🙏

Complication not yet discussed here: #3519352: Content templates, part 3b: store exposed slot subtrees on individual entities. But perhaps it's worth first doing this issue without complicating it with that aspect?

wim leers’s picture

Note: we could choose to tackle #3495625: Remove ComponentTreeItemList::ROOT_UUID from hydration and client-to-server conversion as part of this, by equating \Drupal\experience_builder\Plugin\DataType\ComponentTreeStructure::ROOT_UUID with NULL for the parent column.

I defer to @larowlan.

wim leers’s picture

Title: Spike: Explore storing the ComponentTreeStructure data type one row per component » Spike: Explore storing the ComponentTreeStructure field property one row per component instance
catch’s picture

I think it's worth doing this first, but having #3519352: Content templates, part 3b: store exposed slot subtrees on individual entities in mind while doing it.

There are probably two ways that issue could be done, assuming row-per-component is implemented here:

1. Keep a single field, but add a column for 'slot' (or whatever else is necessary), meaning deltas would span across multiple slots.

2. Add a separate field for each exposed slot.

If those are indeed the two options and there is not some other third option, then they're both compatible with this issue (I think), so it should be fine to do this first without having to pick one in advance.

wim leers’s picture

I intend to get to the bottom of that one tomorrow, but it is reassuring to read you do not anticipate problems with this implementation order 😊

wim leers’s picture

Just caught up on #3519352 — high-level responses at #3519352-38: Content templates, part 3b: store exposed slot subtrees on individual entities.

Makes me want to #22+++++++++++++ even more than I could've anticipated 😄 — as in: "do this first, but keep #3519352 in mind".

larowlan’s picture

Title: Spike: Explore storing the ComponentTreeStructure field property one row per component instance » Spike: Explore storing the ComponentTreeStructure data type one row per component
Issue tags: -blocker
Parent issue: #3520484: [META] Production-ready ComponentSource plugins » #3477428: [PP-1] Refactor (or decide not to) the XB field type to be multi-valued, to de-jsonify the tree, and to reference the field_union type of the prop values
Related issues: -#3495625: Remove ComponentTreeItemList::ROOT_UUID from hydration and client-to-server conversion

Pushed up some work in progress. Will continue with the TranslationTest next as that's the big unknown

larowlan’s picture

Title: Spike: Explore storing the ComponentTreeStructure data type one row per component » Spike: Explore storing the ComponentTreeStructure field property one row per component instance
Issue tags: +blocker
Parent issue: #3477428: [PP-1] Refactor (or decide not to) the XB field type to be multi-valued, to de-jsonify the tree, and to reference the field_union type of the prop values » #3520484: [META] Production-ready ComponentSource plugins
Related issues: +#3495625: Remove ComponentTreeItemList::ROOT_UUID from hydration and client-to-server conversion

cross post

larowlan’s picture

Assigned: larowlan » wim leers

Draft MR up, should be passing linting

I think now is good time to check in and decide if we want to get this mergeable

Referring back to the spike objectives

  1. Determine if this is feasible - yes definitely - TranslationTest is passing, rendering is working
  2. Consider the implications for API consumers like JSON:API - If we add a normalizer for the ComponentInputs typed data this becomes pretty simple
  3. Find out any possible downsides - Alex mentioned that some components won't require all their props to be translatable. This model will allow us to do that on a per component basis as we're one row per instance. I think this also makes purging slots and ContentTemplate tree merging a lot simpler
  4. Size the remaining work that would be required to implement this - I think there's probably 1 or 2 day left to clean up the failing tests (there's a lot!) - many tests are constructing the data in the old (tree+input) format and need to move to the multi-cardinality format.

Assigning to Wim to get a +1 keep going before going any further.

wim leers’s picture

Status: Active » Needs review

Awesome! Thank you for summarizing the current status as well 🙏😊 Excited to review this!

lauriii’s picture

Find out any possible downsides - Alex mentioned that some components won't require all their props to be translatable. This model will allow us to do that on a per component basis as we're one row per instance.

These seem potential benefits of this approach rather than downsides 🤔 Have we considered what are the downsides with this approach? How does this impact performance, flexibility, storage requirements, and developer experience?

I'm also curious, how does having one row per instance help with prop translation? Might be worth explaining the change in more detail in the issue summary because I feel like I'm missing something.

wim leers’s picture

I'm also curious, how does having one row per instance help with prop translation? Might be worth explaining the change in more detail in the issue summary because I feel like I'm missing something.

This bit is specifically what I wanted @larowlan and @effulgentsia to discuss. Per #28, they did discuss that, and @larowlan got the (a)symmetrical translation support working as he mentions in #28.1.

I'd be fine with explaining that in the updated docs/data-model.md rather than the issue summary. I think @larowlan just hasn't gotten to that point yet 😊

wim leers’s picture

catch’s picture

How does this impact performance, flexibility, storage requirements, and developer experience?

On performance, are already additional rows to write on entity saves due to #3521202: Store XB field type's "deps_*" columns in separate table to allow efficient querying, which denormalizes some of the existing information in the JSON field. I think this MR (or a follow-up) will make that completely unnecessary because there's already a column with the component in it. So it should actually be the same, or similar, amounts of database rows with less duplication overall. Even if there are more rows, writing additional rows in a transaction shouldn't make a lot of difference. Reading will get the rows in a single query so should be neutral. Parsing the JSON should be done behind the entity cache ideally, so that should also be neutral once the entity is cached. Or even if not it'll be behind render caching.

For storage requirements, it should help compatibility with #3469082: Add way to "intern" large field item values to reduce database size by 10x to 100x for sites with many entity revisions and/or languages because instead of a single large field that could have a single character change, it will be possible to intern per-component - e.g. when there's a long text input. Otherwise a change to any part of the tree would preclude interning. If/when we add revision pruning outside XB, it may be possible to do something like only prune revisions when they are not removing the last remaining instance of an 'interned' value, so that the full history of changes to individual fields can be preserved, just thought about this now and not sure if it will hold up, but it would be a nice bonus if so. That definitely wouldn't be possible when all the content is in the single JSON blob.

Any kind of auditing or bulk operation on components should be easier - e.g. to find all entities using a specific component, you can query the component column (including from custom views admin listings or similar), this means no bespoke integration with #3521202: Store XB field type's "deps_*" columns in separate table to allow efficient querying to worry about and no JSON queries if that issue hadn't been done.

For DX, if someone is looking around the database tables, it will be a more familiar structure than a JSON blob + separate denormalized dependency lookup table. Apart from looking in the database or working on XB itself, it should be transparent anyway.

Views queries on prop values will still be hard, because that will need to query the JSON column, which will run into all the same issues discussed on #3521202: Store XB field type's "deps_*" columns in separate table to allow efficient querying with regard to JSON indexes, cross database support etc.. However, it will be a simpler JSON structure to query than with the current schema, so can only make that better rather than worse. I don't think views queries on values for this field are a high or even medium priority, and approaches like #3523846: [PP-1] Spike: Explore storing component inputs in separate columns (aka field union), while they would avoid JSON, introduce a lot of cross-table JOINs which can have their own problems and complexity, and would require special handling in views too. So for me the single JSON column with values is the right balance.

It will make things easier for MongoDB, because MongoDB can just store this in jsonb (along with everything else for the entity/revision), and use it natively instead of having to deal with the duplication and custom schema in #3521202: Store XB field type's "deps_*" columns in separate table to allow efficient querying. So while it moves the main field away from a document model, the overall XB database schema moves closer to one again - back to only field storage without custom relational SQL layers on top.

For flexibility, the actual change should be neutral in terms of XB itself. However when it's combined with #3523841: Versioned Component config entities (SDC, JS: prop_field_definitions, block: default_setting, all: slots for fallback) + component instances refer to versions ⇒ less data to store per XB field row we are getting very close to a 'dynamic field union' or 'no entity paragraphs' data model which could potentially be re-usable or adaptable outside of XB itself - e.g. for structured, multi-column fields (think a CD content type with a track listing field, where the track listing has song title, duration, musician entity references etc., or IMDB-style TV show episode listings with duration and actors). Those structured fields can then be incorporated into XB layouts too. Without the dynamic field union, we will either see people continue to use paragraphs or similar models, or try to shoe-horn those kinds of things into dynamic slots even if they should be structured fields sometimes.

This is a long list of benefits or neutral effects, with no actual downsides, but I think that's right.

wim leers’s picture

Assigned: wim leers » larowlan

The big bet we made with XB >1 year ago was that #3343634: Add "json" as core data type to Schema and Database API would get fixed, which with the last core minor release (11.2) prior to XB 1.0 in the final stages now, is guaranteed to not happen.

So the primary goal of this MR: decomposing the 2 big JSON blobs per revision (tree and inputs) that we've been discussing for >1 year in many places, most recently in #3457504: XB field type: calculate all dependencies, store them, surface in new Component "Audit" operation. This MR must do it in a manner where:

The approach @larowlan went with is option 1 that @catch listed in #22.

Reviewed this entire 71 files, +1908, -1680 MR 😄

Posted 67 remarks, of which 19 were trivial comment nits that I already applied. The remainder are either observations to help the next reviewer (ℹ️), excitement/admiration/applause (🤩) or questions 😄

Light bulb moments

While reviewing, these were the most important "aha!" moments:

  1. The (a)symmetrical translatability support concerns in #31 are solved by core's require_all_groups_for_translation, which is used by the image field type already 👍
  2. This MR's new ValidParentAndSlotConstraintValidator allows trivially adding support for ContentTemplates: there's already a @todo, the remaining work to make it fully validatable is trivial, and makes #3519352: Content templates, part 3b: store exposed slot subtrees on individual entities completely obsolete AFAICT! This MR's introduction of storing every component instance separately, with an optional parent_uuid and optional slot is what makes this easy (instead of very hard in HEAD) 👍

    IOW: this does address the meta (#3520449)'s feature: content entities' XB component trees must be able to populate the exposed slots provided by the corresponding ContentTemplate.

  3. A single additional normalizer (for the ComponentInputs data type) that would be trivial to implement would be sufficient to achieve JSON:API read/write support for content entities with XB fields! Which means XB would be able to leap ahead of LB on that front already, because #2942975: [PP-1] Expose Layout Builder data to REST and JSON:API remains unsolved. The difference is that XB started with strict schema + validation, so the big "ensure the normalization can be interpreted by front-end developers" problem is already solved. (It'd even comply with the recommended best practice at #2926507: Discourage @FieldType-level normalizers, encourage @DataType-level normalizers, to strengthen the API-First ecosystem.)
    EDIT: that's what @larowlan independently concluded in #28.2! 👍

Issues we could close if this lands

AFAICT this allows us to close, @larowlan should confirm:

  1. #3495625: Remove ComponentTreeItemList::ROOT_UUID from hydration and client-to-server conversion
  2. #3462235: [PP-1] Add typed value-objects for the component tree structure
  3. #3519352: Content templates, part 3b: store exposed slot subtrees on individual entities

Questions

  1. While I know it was not a goal of this issue, his does not yet address the meta (#3520449)'s feature: asymmetric translation will need some explicit inputs to be locked, because some explicit inputs may be considered to be not translatable — for example an image input of some component.

    AFAICT this MR does not make that neither more difficult nor easier to achieve. In HEAD, it would have required some extra per-component instance metadata. Here, it would, too. In HEAD, it'd probably have had to live in the data contained in the ComponentInputs data type. With this MR in, that would still have to be the case.

    So I think this MR is neutral for that.

    EDIT: that seems to match what @larowlan independently wrote in #28.3 👍

Conclusion

A very strong "+1, yes please! 😄" to @larowlan's Assigning to Wim to get a +1 keep going before going any further..

catch’s picture

I think option #1 vs #2 from #22 is still to be determined in #3519352: Content templates, part 3b: store exposed slot subtrees on individual entities. I think there might be some confusion between 'slot' and 'exposed slot' in my original comment either between me and Wim in #34 or possibly just by me.

If we did option #1, I was thinking we would probably have to add an additional 'exposed slot' column to map the row to the exposed slot in #3519352: Content templates, part 3b: store exposed slot subtrees on individual entities (in that issue, not this one). e.g. all the data for all the exposed slots in one field instance.

If we did option #2, then the schema added here would be unchanged, instead each exposed slot would have a field instance.

Or am I misunderstanding and this already implements #1 because slot === exposed slot in this context? If so the confusion is all mine.

wim leers’s picture

Status: Needs review » Needs work

@catch in #33:

Even if there are more rows, writing additional rows in a transaction shouldn't make a lot of difference

Good reassurance, this I'm less familiar with 🙏👍

storage requirements, it should help compatibility with […] because instead of a single large field that could have a single character change

Exactly!

ot removing the last remaining instance of an 'interned' value, so that the full history of changes to individual fields can be preserved, just thought about this now and not sure if it will hold up, but it would be a nice bonus if so.

Wow, great insight — that would be amazing! 🤩

Any kind of auditing or bulk operation on components should be easier - e.g. to find all entities using a specific component, you can query the component column (including from custom views admin listings or similar

Exactly! IOW: this would basically solve make #3522953: [later phase] Make Component `audit` operation performant/scalable simpler, and would allow us omitting config: experience_builder.component.* dependencies from #3521202: Store XB field type's "deps_*" columns in separate table to allow efficient querying's component_tree_depencies table. Because that's essentially duplicating that same bit of information now.

For DX, if someone is looking around the database tables, it will be a more familiar structure than a JSON blob + separate denormalized dependency lookup table. Apart from looking in the database or working on XB itself, it should be transparent anyway.

💯 — this MR single-handedly makes XB much easier to wrap your head around. Much becomes deducable.

However, it will be a simpler JSON structure to query than with the current schema, so can only make that better rather than worse.

Indeed! To be more precise:

  • from 1 massive JSON blob per XB field revision
  • to 1 small JSON blob (with one less level of nesting too) per component instance per XB field revision

However when it's combined with […]

That's what I'm starting work on right now! 🤓🥳

This is a long list of benefits or neutral effects, with no actual downsides, but I think that's right.

💯


@catch in #35:

You're right that that choice is not finalized in this MR. But this bit in ValidParentAndSlotConstraintValidator definitely lean towards option #22.1 aka storing an exposed slot name in the slot field property/column of an XB field item:

    // @todo 👉️ For 'bonsai' trees, the parent may not be in the corresponding
    //   parent list but in a ContentTemplate for the parent entity.

Which at least I interpreted as @larowlan intending to implement it this way in this MR, which would make Or am I misunderstanding and this already implements #1 because slot === exposed slot in this context? If so the confusion is all mine. almost true: it's not quite implemented yet, but AFAICT @larowlan intends it to be.

This is why I tried to deduce how @larowlan intends to implement this and the required code would indeed be trivial.

Perhaps we're both missing something? :D

catch’s picture

Good reassurance, this I'm less familiar with

There's some background in #3217783: Configuration management performance regression - slow config:import. I don't think we were actively making use of this behaviour (or necessarily knew about it at all) until recently, for entities it's been like this since we added transaction support to core. Either way the write to one field table happens in a single query anyway (just double checked), so it may even behave exactly the same before/after in terms of write performance or at least very similarly.

wim leers’s picture

lauriii’s picture

Issue tags: +beta blocker
wim leers’s picture

Title: Spike: Explore storing the ComponentTreeStructure field property one row per component instance » Store the ComponentTreeStructure field property one row per component instance
Priority: Major » Critical

The spike has proven itself, as I already said in my review in #34, but especially now that it's green!

Excited to review this 85 files, +3644, -3221 diff in depth tomorrow! 😄

@larowlan indicated he'd be doing a self-review first thing tomorrow, so leaving assigned to him for that. 👍

larowlan’s picture

Assigned: larowlan » Unassigned
Status: Needs work » Needs review
Issue tags: -Needs issue summary update

Did another pass and was able to
* Remove the new UniqueConstraint validator in favour of putting it into ComponentTreeStructure
* Noticed we weren't using ComponentTreeStructure on field default values, was tricky, but was able to add that
* Made validation property paths consistently use dot notations e.g. something.1.uuid instead of a mix of that and square brackets - something[1][uuid]
* Another pass on docs

Added comments to the MR to help reviewers

This is ready for reviews now

wim leers’s picture

Assigned: Unassigned » wim leers

🥳🤓

wim leers’s picture

Assigned: wim leers » Unassigned
Status: Needs review » Reviewed & tested by the community
Related issues: +#3526127: Ensure deterministic config export order of config-defined component trees
StatusFileSize
new202.43 KB

I think the true test of a well-designed system (besides adoption, vibrant ecosystem, etc. — all of which by definition cannot yet exist) is:

Well of course it works like that, that all looks like it makes total sense.

IOW: when it seems so evident that the data and logic is structured in this particular way, that it's hard to imagine any other way.

I think XB is now entering that territory with this MR. 🤓🤩

It's amazing to see how this single (massive!) MR completely transforms the most essential part of XB (the way it stores component trees in both content entities as fields and in config entities), and we can be confident that it'll A) work (thanks to tests), B) scale to many different uses (thanks to the 3 different config entity types that use it, and kinda 4).

If it were so evident that this was the right approach, we would've written it like this at the very start. But we didn't. It required iteration. And the uses, the tests, the validation logic all needed to be structured in a sufficiently sensible manner for this massive refactor (by a single (very capable) person over the course of a few days!!!) to be achievable.

IMHO this is the biggest achievement yet of the team working on XB's back end. And it's thanks to literally all of those people having contributed — including all the front end work that uses that back end and that end-to-end tests are exercising the back end through the front end.

See the remaining open threads — they highlight some of the crucial improvements.

Bonus delight: @larowlan's fine test string choices:

  • And we laugh like soft, mad children
  • Smug in the wooly cotton brains of infancy

🤣


It also allowed me to:

  1. close #3471026-13: Harden UUID validation in ComponentTreeStructureConstraintValidator
  2. reduce scope and stable blocker tag for #3495625-14: Remove ComponentTreeItemList::ROOT_UUID from hydration and client-to-server conversion
  3. clarify #3499632-13: Remove `ClientServerConversionTrait` (C→S) and `ComponentTreeItemList::getClientSideRepresentation()` (S→C) in favor of (de)normalizers
  4. reduced scope and precise remaining steps for #3519352-41: Content templates, part 3b: store exposed slot subtrees on individual entities
  5. create a nicely scoped follow-up for the last crucial DX improvement for config management: #3526127: Ensure deterministic config export order of config-defined component trees

Finally, this is what a single simple component tree on a content entity now looks like in the DB:

… and that component_id column will evolve in the next issue @larowlan is working on: #3523841: Versioned Component config entities (SDC, JS: prop_field_definitions, block: default_setting, all: slots for fallback) + component instances refer to versions ⇒ less data to store per XB field row.

  • wim leers committed d85b29ac on 0.x authored by larowlan
    Issue #3468272 by wim leers, larowlan, catch, longwave, effulgentsia:...
wim leers’s picture

Status: Reviewed & tested by the community » Fixed
larowlan’s picture

Status: Fixed » Needs work

Awesome to see this land!

Full credit to Jim Morrison poetry for the test strings.

There's a minor issue here https://git.drupalcode.org/project/experience_builder/-/merge_requests/1... around DX consistency from a late change, I've reopened this to revert that (separate MR). Creating that now

larowlan’s picture

Status: Needs work » Needs review

Opened a follow up for a couple of things spotted in review

  • wim leers committed d797ff02 on 0.x authored by larowlan
    Issue #3468272 by wim leers, larowlan: Follow-up: rename `parent` field...
wim leers’s picture

Status: Needs review » Fixed

Thanks for the posthumous review/confirmation of the tweaks I made to your epic MR, and merged the follow-up 👍 😊

wim leers’s picture

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.