-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Core Data: Draft a type for an Entity's config paramater #39481
base: trunk
Are you sure you want to change the base?
Conversation
baseURL: string; | ||
|
||
/** Arguments to supply by default to API requests for records of this entity. */ | ||
baseURLParams: { context: Context }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type here is more of
baseURLParams: { context: Context }; | |
baseURLParams?: Record<string, string> & { context?: Context } |
We could combine this with WithLiterals to get both :
It would read similarly to: const rootEntitiesConfig : DeepReadonly<EntityConfig[]> = [ /* ... */ ];
type DeclaredConfigTypeUnion = typeof rootEntitiesConfig[keyof typeof rootEntitiesConfig]; |
I thought I left a comment with that but I can't find it anywhere – here's the type I used in #39025: export interface EntityConfig {
baseURL?: string;
baseURLParams?: EntityQuery< any >;
getTitle?: ( record: unknown ) => string;
key?: string;
kind: string;
label?: string;
name: string;
plural?: string;
rawAttributes?: readonly string[];
title?: string;
transientEdits?: { blocks: boolean };
} |
* Some entities have an associated title, such as the name of a | ||
* particular template part ("full width") or of a menu ("main nav"). | ||
*/ | ||
getTitle( record: Record ): string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be null
getTitle( record: Record ): string; | |
getTitle( record: Record )?: string; |
key: string; | ||
|
||
/** | ||
* Collection in which to classify records of this entity. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another word would be a "namespace", since some frameworks refer to database tables as "collections". Namespace isn't perfect too, though – I guess we could use either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah it still puzzles me and I think the reason is that this kind
value connotes different things at the same time. I'm reluctant to use the term namespace because I think that's a back-justification. one of the effects is namespacing, but it's really not used that way.
namespace
is used as part of the API to get versions of the resources, e.g.wp/v2
orwpcom/v1.1
.- it's clearly being used as categorization or classification when contrasting
postType
andtaxonomy
. in cases such as in callinggetEntityRecord
it definitely feels more like "this general kind of entity record" as a grouping term rather than "the entity records provided by this plugin" which is generally how we use "namespace" elsewhere in the project
probably what's throwing us both off is that getOrLoadEntitiesConfig
was built upon kind
when in fact that function serves a subtly different purpose; more again an incidental design element related to optimization rather than intent.
// Unstable properties | ||
|
||
/** Returns additional changes before applying edits to a record of this entity. */ | ||
__unstablePrePersist( record: Record, edits: Edit[] ): Edit[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
__unstablePrePersist( record: Record, edits: Edit[] ): Edit[]; | |
__unstablePrePersist( record: Record, edits: Edit[] )?: Edit[]; |
/** | ||
* Which transient edit operations records of this entity support. | ||
*/ | ||
transientEdits: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is optional as well
transientEdits: { | |
transientEdits?: { |
__unstablePrePersist( record: Record, edits: Edit[] ): Edit[]; | ||
|
||
/** @TODO: What is this? Used in `canEdit()` */ | ||
__unstable_rest_base: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what this is at the moment, but it's optional
__unstable_rest_base: string; | |
__unstable_rest_base?: string; |
/** Translated form of human-recognizable name or reference to records of this entity. */ | ||
label: string; | ||
|
||
/** @TODO: What is this? */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question! I don't remember, we'll have to find out.
* in the database as well as the rendered version with shortcodes replaced, | ||
* content texturized, blocks transformed, etc… | ||
*/ | ||
rawAttributes: (keyof Record)[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is optional and assumed to be an empty list if missing. Also, I don't think it can be anything else than a string
.
rawAttributes: (keyof Record)[]; | |
rawAttributes?: string[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's fine, keyof Record
should be a string but this constraint mandates that it's a field we actually define in the Record type. not relevant if we don't parameterize by record, but I've added in here at least for thinking about this type because clearly the config value is in effect parameterized by the record type.
if we remove that inherent coupling we don't sacrifice much, but for example, we miss out on guidance in getTitle
.
removing that coupling is a real option. like much of this project these properties tend to be added over time as need arises and so they're not necessarily orchestrated as a unified whole. if practical, I think it would be great to keep it because then you would be able to write getTitle
and have it show you the available fields in the record that you could use.
// @ts-ignore | ||
export interface EntityRecord< C extends Context > {} | ||
|
||
export interface EntityConfig< Record extends EntityRecord<any> > { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What else can we call it? This name conflicts with the built-in type Record
. Perhaps R
wouldn't be too terrible? Or _Record
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if parametrizing this will play along with as const
/DeepReadOnly
and the lookup table approach. If not, perhaps we could hardcode the key and the context in TypeScript, separately from the config, and then constrain the EntityConfig
type to only express these hardcoded values? But that seems backwards, as if the type was the actual config.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure what I was thinking there with Record
. nevertheless, we should consider all of this possibly junk-code because I was laser-focused on the other aspects while writing it out.
See #39025
Please ignore this actual PR because it's only meant as a place to discuss the type and work in progress in #39025.