It would be sweet if we had a nicer syntax for hook_schema.
Imo, if we do it right, then shorter = easier to read and write.

D8:
Whether we move this to an event, is a different question, and independent of this proposal.

EDIT (donquixote):
I originally had two ideas about this, but find one a lot more convincing. As so far I am the only one active on this issue, I take the freedom to remove the other proposal.
I recently did some experiments in D7, and this is the (working) result: http://drupal.org/project/injapi
The current proposal is mostly taken from there.

Method chaining / "fluid" syntax for hook_schema().

The hook_schema() would receive an argument that would be the starting point for the method chaining game.
(I say "$api" for "InjectedAPI", following a pattern I use in my contrib projects. Feel free to suggest otherwise.)

The draft is taken directly from injapi module:
http://drupalcode.org/project/injapi.git/blob/refs/heads/7.x-1.x:/exampl...

/**
 * Implements hook_schema()
 */
function hook_schema($schema) {

  // That's the table.
  $table = $schema->table('comment');

  // Primary key.
  // "field_id" automatically gives us auto-increment, and registers this field as the primary key.
  $table->field_id('cid');

  // Foreign keys
  // field_idForeign can take optional parameters to automatically create relations.
  $table->field_idForeign('pid');
  $table->field_idForeign('nid', 'node', 'nid', 'comment_node');
  $table->field_idForeign('uid', 'users', 'uid', 'comment_author');

  // Data fields
  // Most field types have extra parameters for stuff that is special to this type. E.g. varchar length.
  // required() has a second parameter for the default value.
  $table->field_varchar('subject', 64)->required(TRUE, '');
  $table->field_varchar('hostname', 128)->required(TRUE, '');
  $table->field_seconds('created')->required(TRUE, 0);
  $table->field_seconds('changed')->required(TRUE, 0);
  $table->field_unsigned('status', 'tiny')->required(TRUE, 1);
  $table->field_varchar('thread', 255)->required();
  $table->field_varchar('name', 60);
  $table->field_varchar('mail', 64);
  $table->field_varchar('homepage');
  $table->field_varchar('language', 12)->required(TRUE, '');

  // Field descriptions
  // We keep these separate, to have the upper part more readable.
  // This said, we could instead just put the ->description() on each field directly.
  $table->describeFields(array(

    // Id columns
    'cid' => 'Primary Key: Unique comment ID.',
    'pid' => 'The {comment}.cid to which this comment is a reply. If set to 0, this comment is not a reply to an existing comment.',
    'nid' => 'The {node}.nid to which this comment is a reply.',
    'uid' => 'The {users}.uid who authored the comment. If set to 0, this comment was created by an anonymous user.',

    // Data columns
    'subject' => 'The comment title.',
    'hostname' => "The author's host name.",
    'created' => 'The time that the comment was created, as a Unix timestamp.',
    'changed' => 'The time that the comment was last edited, as a Unix timestamp.',
    'status' => 'The published status of a comment. (0 = Not Published, 1 = Published)',
    'thread' => "The vancode representation of the comment's place in a thread.",
    'name' => "The comment author's name. Uses {users}.name if the user is logged in, otherwise uses the value typed into the comment form.",
    'mail' => "The comment author's e-mail address from the comment form, if user is anonymous, and the 'Anonymous users may/must leave their contact information' setting is turned on.",
    'homepage' => "The comment author's home page address from the comment form, if user is anonymous, and the 'Anonymous users may/must leave their contact information' setting is turned on.",
    'language' => 'The {languages}.language of this comment.',
  ));

  // Indexes
  $table->index('comment_status_pid', array('pid', 'status'));
  $table->index('comment_num_new', array('nid', 'status', 'created', 'cid', 'thread'));
  $table->index('comment_uid', array('uid'));
  $table->index('comment_nid_language', array('nid', 'language'));
  $table->index('comment_created', array('created'));
}

Implementation

The implementation can be copied and adapted directly from injapi module.

The objects ($schema, $table, $field) used in here are just temporary for the purpose of this hook, and will not be used anywhere else in the db engine.
The $schema object might be created new for every invocation, or we use the same all over.
The result of a hook invocation will still be a huge array, after all is done.

Benefits

- Nicer to read (imo).
- Faster to type.
- Less scrolling.
- More visual structure in the code.
- Easier to focus on the intention of things, rather than the technical details.
- Well-known patterns such as "auto-increment id" are shortcutted, so you don't have to guess that from the values.
- Possibility for immediate sanity checks in the various methods, so that the array structure collected in $schema can be always sane.

Cons

- A tiny overhead, but that doesn't matter, because it is only on rebuild.
- No idea if we have anything other planned for hook_schema().
- Not sure what to do with hook_schema_alter().

Thoughts

Memory concerns?
We still have the option to run this thing separately per module, with a new $schema object per invocation. I don't think this is actually necessary, but the option exists.

Comments

donquixote’s picture

Update:
In my own projects I went to calling this pattern "Injected API". The argument is then always named "$api". I am going to change the issue description accordingly.

donquixote’s picture

This can be seen in action here:
http://drupalcode.org/project/injapi.git/blob/refs/heads/7.x-1.x:/exampl...
(and changing the issue description, again)

donquixote’s picture

Issue summary: View changes

Link to a more recent example / draft, with a slightly different syntax.

donquixote’s picture

Issue summary: View changes

Updated issue summary to describe the latest proposal, and not distract with details we are going to discard anyway.

donquixote’s picture

Issue summary: View changes

Updated issue summary.

donquixote’s picture

Issue summary: View changes

Updated issue summary.

donquixote’s picture

An alternative would be to move to yml files, like with routes.
(far away from saying it should be CMI !!)
That would still be more verbose than what is suggested above, but nicer to type than PHP arrays..

donquixote’s picture

Issue summary: View changes

Replacing "$h" with "$api"

donquixote’s picture

Title: Shortcut syntax for hook_schema(). » "Fluid" syntax for hook_schema() (method chaining).

Updated summary, now we also update the title.

donquixote’s picture

Related:
#432440: Update Schema API to make it more usable

I should mention that this other issue is trying to solve a different problem, and has nothing to do with the syntax within hook_schema().

This issue here, on the other hand, is only about DX syntax candy within hook_schema(), nothing more.
It does not plan to change the internal array structure.

Crell’s picture

I actually rather detest hook_schema in its entirety. I'd rather just kill it in favor of something cleaner and less Drupal-specific, per the linked issue. Adding utility routines inside hook_schema is just putting lipstick on a pig.

donquixote’s picture

I thought the linked issue was more thought for the internal implementation of "writing the schema stuff to the db", and for hook_update implementations.

How does the alternative look like? Crud?
That's the same controversy again as we have with CMI for routes: persistent state + crud, vs info + cache. Imo, whatever we do with state + crud, it always means that modules need to do a lot of babysitting, which I would prefer them to not have to care about.

This said, I don't mind moving towards events or yml.
I wonder what other systems do, I did not do any research on that.

donquixote’s picture

Though yes, I know doctrine. I just think we are far away from that, and the particular implications of that would not fit for us.

donquixote’s picture

Also, don't we have enough bloodshed in D8 already.. shouldn't we leave some killing for D9?
The hook_schema and "huge array of definitions" (not talking about implementation) as is doesn't make realworld problems afaik, and this particular change is totally harmless and can even be backwards compatible.

donquixote’s picture

And yes, this is all about lipstick. Very nice lipstick.
And then again, it's not. It's giving a new face to the pig. And then at some day replacing the pig behind, if we feel that way.

Crell’s picture

If we're going to come up with a new syntax we expect everyone to use inside hook_schema(), then it seems there's little point to it unless we also make sure it's a syntax we intend to be usable long-term. And then, it's only a short skip to removing hook_schema() in favor of some non-hook way of defining tables. (Since the hook, like so often, introduces some weird dependencies at times.)

My thought from the other issue (or after a year of further thinking) is that we need to, first, provide an introspection system for the DB layer to tell us what the state of a table is. That involves defining some table object that represents the introspected data, which we can then retrieve at any time. (schema.module in contrib already has the MySQL code we'd need, it just needs to get OOPified.) Then once that class is defined, declaring a table becomes a matter of a module providing such a class, and the DB layer can round-trip it. ($table = new MyModuleTable(); $conn->schema->createTable($table);) DDL queries are then query builders in the same vein as our other query builders, chained like everything else.

Make sense? (I don't know how much of that is feature-freeze material, and I've been kinda busy with WSCCI which is why I've not gotten back to it.)

donquixote’s picture

Thanks for picking this up!

Since the hook, like so often, introduces some weird dependencies at times.

That would be, e.g. a table structure depends on the definition of a content type, a field, etc?
I don't see this as a problem necessarily.
You need to be aware of the dependencies when you design a module, and then design a clearly defined food chain. If you ignore that, you get into trouble. But those dependencies do not exist because of the hook, but because of what you want to achieve.

But maybe you mean sth else?

declaring a table becomes a matter of a module providing such a class

I think Zend does it that way (or did, when I used that ages ago).
Totally doesn't help with dynamic schema definitions - unless you play with code generation.
I always found that boilerplatey and stupid, writing those classes.

And rightfully, Doctrine lets you write yaml files instead, which lets you focus on the actual definition of the table, instead of the boilerplate getters, setters and friends. This yaml feels very much like our hook_schema(), with some additions.
From there you get those classes via code generation, and you subclass them to implement custom behavior.

For Drupal I don't really believe in "one class per file" approach:
- It does not help for dynamic schema definitions (e.g. for content types)
- It does not allow multiple modules to participate in the schema definition. No, I don't count subclassing as a solution, that is too one-dimensional.
- It creates a lot of duplicate and meaningless code.

I'd rather see
- some code to produce table definitions (hook_schema, yaml, etc)
- operations that are used internally to create those tables in the db.
- generic classes for tables and fields/columns, which are instantiated with specific configuration, instead of being subclassed. Yes, this would give you the introspection you want.
- reusable "behaviors" which can be attached to tables or columns.
- a query builder similar to dbtng (or just keep that)

Actually I don't really care about the other points.
The main thing is, as a module developer I want a pleasant way to define my schema, without doing anything redundant or bureaucratic. What the system does with that, is not part of this issue: It can either just remember the schema somewhere, or if you want, generate those classes as class-per-table, like Doctrine does.

If we compare
- Doctrine-style yaml files (you can also have XML, but seriously who wants that :) ) -> static
- Doctrine-style yaml + php (I think I saw that somewhere)
- hook_schema() + alter with nested arrays
- hook_schema() + alter with method chaining, as suggested here
- a hybrid hook_schema() which allows nested array return value as well as method chaining.
- the same, but moving that to schema builder events, schema factories, or the like.

Some details aside, these are all exchangeable. Except
- some work better than others for dynamic schema definitions
- there's this old "NIH" argument.
- Doctrine afaik has some additional keys to attach behaviors. This is pretty cool, but nothing stops us from doing the same.
- hook_schema + alter is better at letting multiple modules participate in the definition process.

we need to, first, provide an introspection system for the DB layer to tell us what the state of a table is. That involves defining some table object that represents the introspected data, which we can then retrieve at any time.

We can easily have our introspection objects today, with a few classes instantiated with existing hook_schema definitions.
I can imagine very little that this object could tell us, where we would absolutely need a "class per table" approach. Neither generated nor hand-written.
And due to our modularity, we are unlikely to hardcode any business logic into those classes.

donquixote’s picture

Btw,

Since the hook, like so often, introduces some weird dependencies at times.

there is this issue #1446808: Let plugin managers announce changed definitions
and this post in gdo suggesting a "dependency matrix": http://groups.drupal.org/node/267163#comment-850373
(yes, you probably know that already)

Crell’s picture

Actually I was referring to the bootstrap knot of doom that hooks result in. Plus the lazy load questions around specialty hooks.

I am not suggesting forcing a class name per table. I'm suggesting wrapping the information about a table into a typed object, which is then bidirectional.

$table = $conn->schema()->getTable('foo');
// $table is an instance of Database\Schema\Table;
$conn2->schema()->createTable($table);

class MyTable extends Database\Schema\Table {
  // Define the structure here, whatever it is, haven't thought that through yet.
}

$conn2->schema()->createTable(new MyTable()):

Dynamic schemas are fine with that, because they can create and populate a Table object whenever they like and pass that in. But they can also then introspect tables, too.

Even if we offered a YAML file for module devs as well (wait, I thought you didn't like YAML for Routes? :-) ), we'd still need such an in-PHP representation of a table anyway because we are *not* baking a YAML dependency into the database system. It is actually rather analagous to Routes (PHP object for the definition, ability to dump out to or read in from whatever other serialized formats you feel like writing as a DX convenience). That PHP object has to come first, though.

changeTable() I see going away in favor of a query builder that feels a lot like the insert/update/delete builders.

donquixote’s picture

Actually I was referring to the bootstrap knot of doom that hooks result in. Plus the lazy load questions around specialty hooks.

I don't see that problem, esp with hook_schema(). If you could explain .. :)
The only issue I could see is, you are creating a content type, and instead of doing the schema change directly, you need to wait for a "schema rebuild" to do that for you? Not sure if that is even the case today..

wait, I thought you didn't like YAML for Routes? :-)

yaml on itself is great.
The issue I have is yaml for static + something else for dynamic + yet something else for altering, that is 3 different "languages" to learn. With nested definition arrays, you learn the static definition first, and then the rest is just obvious. You can open a random *.install file and look for hook_schema(), and you know it all.
We might get used to it if this becomes a common pattern.

This being said: yaml + alter + dynamic, original hook_schema, "fluid" hook_schema, they are all in the same boat if compared to what you seem to be proposing .. so I'd like to get over those basic decisions first, before we go back to DX bikeshed (which this issue was originally about)

Even if we offered a YAML file for module devs as well (wait, I thought you didn't like YAML for Routes? :-) ), we'd still need such an in-PHP representation of a table anyway because we are *not* baking a YAML dependency into the database system. It is actually rather analagous to Routes (PHP object for the definition, ability to dump out to or read in from whatever other serialized formats you feel like writing as a DX convenience). That PHP object has to come first, though.

Yes, sure.

// (somewhere in core)
// get schema from yaml, hook_schema() or others
$schema = drupal_collect_schema();
// create your introspection table objects
foreach ($schema as $name => $table_info) {
  $table = $db->loadOrCreateTable($name);
  $table->setConf($table_info);
  $table->save();
}
// TODO: Why not make schema an object as well :)

// (somewhere in a module)
function hook_update_N($db) {
  $table = $db->getTable('comments');
  $table->changeFieldSetting('title', 'length', 2047);
  $table->save();
}
function hook_schema($schema) {
  $table = $schema->table('comments');
  // ouch.. this is now a wrapper thingie, whereas in hook_update_N() you are dealing with a "real" table object. This certainly might feel inconsistent.
  $table->field_id(..)
  // OR
  return array(...)
}

Not sure what else you want to do with the introspection table object.
My point is, the average module should not be writing a MyTable class, but just provide its definition, so core can just instantiate the generic Table class.

The code above is using the table as an "ActiveRecord". I'm not sure yet that is a good idea.
I always had the idea that the representation of an object as-it-is-now should be separate from the object as-i-want-to-modify-it. Similar to that the representation of an entity-in-the-db should be separate from entity as-i-want-to-render-it.

$table = $db->getTable('comments');
$table_to_update = $table->createActiveRecord();
assertEqual($table->getDefinition(), $table_to_update->getDefinition());
$table_to_update->addField('test', ..);
assertNotEqual($table->getDefinition(), $table_to_update->getDefinition());
$table_to_update->save();
assertEqual($table->getDefinition(), $table_to_update->getDefinition());

I think this depends what else we want to use the table object for.

Crell’s picture

As you see in the other issue, we were rather stalled on the question of builders vs. state objects for DDL queries. (ie, db_change_table('tablename')->addColumn(...)->execute() vs. the load/save example you have.) There's decent arguments both ways, and we never came to a conclusion on that by the time D7 hit freeze. Since then I've decided my preference is for create table and "what is this table" to be state objects, but change table to be a builder. That way we avoid having to deal with "here's two objects, magically figure out how to turn one into the other", which is a complication I don't want.

drupal_get_schema() had some horrible knots in early bootstrap vis a vis module_list(), the value of which changed depending on when in bootstrap you called it because it cached values differently depending on how it was last called. It was seriously broken steaming pile. That has fortunately been largely cleaned up now in D8 (thanks, chx!), but hook_schema, as a hook, still depends on modules. I do not like the idea of the DB routines being dependent on modules, and on at least some drivers certain query builders are dependent (or were at one point dependent) on the schema, which in turn makes those drivers dependent on a fully running Drupal instance, which is doubleplusungood. Allowing the drivers to introspect themselves and learn what the schema is when needed keeps things nicely decoupled. Once you have that, defining new tables using the same data object is a no-brainer.

That's basically the logic that led me to my current position.

donquixote’s picture

Nice, I think I'm getting more of a bigger picture now :)
I think the solution is to properly slice the responsibilities and dependencies.

Here is how I imagine it could work:

Module schema definitions:
hook_schema(), yaml or similar (+ alter) tell us how modules want the schema to be like.
This has to depend on modules naturally. But we only use it during "rebuild time".

Stored schema definitions:
In addition, we have to remember how the schema is right now, independent of how modules want it to be. This information can be independent of modules, and available at runtime early in the request.
"remember" can mean CMI or any persistent storage we have available. It could be remembered in the database, but only if we manage to "protect this from itself" (so probably better not).
This schema information will have the basic table definitions, plus any meta info that we like.

Active Record:
$table->save() "active record" writes a schema definition both to the schema storage, and runs the queries to actually create or modify the tables in the database.
This can be used any time to quickly change a schema, at the developer's own risk. E.g. after creating a field, we could just directly say $schema->createTable('my_field')->addColumn(...)->save().
And it will be used in core, on "rebuild time", to bring the schema back to the structure intended and described by modules.
Note: This may conflict with hook_schema(), e.g. if hook_schema_alter() adds an additional column, that our module does not know about. See below.

Query engine:
db_change_table('tablename')->addColumn(..)->execute() is just a query builder engine which only talks to the database, but has no idea of schema definitions within Drupal.
We could use that within the implementation of the Table "active record", but probably no other modules will use it.
Whether we actually need this thing, I dunno.

Schema rebuild:
"Rebuild" means that the schema will be reset to the state that modules intend (via yaml, hook_schema + alter, etc). Any previous changes done with direct calls to $table->save() will be overridden by the information from hook_schema(). So if the field module creates a table, and on the next rebuild it doesn't know about that table anymore, the table will be wiped (*).

This gives us a reliable way to clean up a messed-up database structure and turn back to the structure we expect.

(*) We need a way to avoid unintended data loss on those rebuilds. We could say that harmful operations are not executed, and a warning + diff is sent instead - so the module developer has a chance to resolve it in hook_update_N(). (I didn't really check how we do that today, might be we already do sth smart there?)

Syntax on $table and in hook_schema():
We could let hook_schema() and the active record thing use the same table class, or at least methods that behave similarly.
On the other hand, I would like hook_schema to be purely declarative. Any ->save() should not be executed within there.
I think we should postpone that until after we have a plan for the other things.

3rd party code?
A lot of this sounds like we could find it in 3rd party code. Otherwise, we could code that as an independent library and then bring it back to Drupal :)

DISCLAIMER:
I have not really studied the other issue yet, so some of that might change my mind.

donquixote’s picture

Btw, instead of letting modules use $table->save(), we could also allow them to request a partial schema rebuild - e.g. only for the module's own tables. Not sure if this could bring us any trouble, e.g. if a table "changes its owner" from module 1 to module 2.

Crell’s picture

The "Rebuild" process is the one that I don't think is reasonable. That requires an awful lot of involved logic that has to know about specific details of certain database engines and what order certain operations can happen in, what operation combinations cannot happen together, etc. There's also potential data loss situations when fields change their type, which really ought to be handled manually. I'm not convinced that's feasible in practice.

The builder-vs-AR-style question is exactly what the other issue was about. I think we've about rehashed that whole issue by now and should probably merge them. :-)

FTR: I don't think hook_schema_alter() should be allowed to exist. It's a heisenbug waiting to happen.

Also consider that in Drupal 8, between Entity API and CMI, I expect the number of DB tables that modules define should drop dramatically. We may be over-engineering this question for something that will be of declining use. We're also now well outside the realm of what can be done in the next 2 weeks, esp. with most people focused on the main initiatives, and I doubt this level of rebuild is viable post-freeze.

donquixote’s picture

There seems to be the general controversy about "collect info and rebuild" vs "allow modules to do crud operations on an existing structure". (or do both)

The D7 equivalent is hook_install() / hook_schema() on the one hand, and hook_update_N() on the other hand. (and in this case you need both)

hook_schema() means I describe how I want the table structure to look like right now.
hook_update_N() means I describe the operations to get from the current structure to the structure that I want.

If I understand you correctly, you propose to ditch hook_schema() entirely, so that in hook_install() I would have to do operations very similar to hook_update_N(). (only that I would know that none of those tables exist yet).

As a module developer, I enjoy writing and modifying hook_schema(), but I hate writing hook_update_N().
So, I would like to propose something to turn this around :)

  1. You write your first hook_schema() (*).
  2. You install the module, everything happens as we know it. Except that the hook_schema() is remembered somewhere.
  3. You modify the hook_schema().
  4. You use a drush command to generate your hook_update_N() (*) code, based on a comparison of the old and new schema. This could be placed in a dedicated file or class per update, if you want..
  5. You can do manual modifications to the generated hook_update_N().
  6. (every time you re-run the drush command, your changes are wiped. your bad. (we could go the extra mile and automatically merge instead of wiping)
  7. Drupal can run a generic test, to check that your modified hook_update_N() will indeed result in the intended table structure.
  8. Drupal might also generate stub test cases, to check if your data will be correctly preserved / converted.
  9. You run drush updb, and the schema changes.

This seems to me like an awesome-DX solution.

(*) I say hook_schema() and hook_update_N() all the time, but this could be replaced by something else - event subscriber classes, yaml, whatever.

EDIT:
This does not account for dynamic schema changes outside of module updates, or hook_schema() depending on dynamic data. In this case, the developer needs to do more stuff manually in hook_update_N().

Crell’s picture

I think we're talking at 2 different levels.

The database system itself, independent of Drupal in any way, needs to have the following:
1) A way to extract a table definition object from an actual database.
2) A way to take that table definition object and create the table it represents, round-tripping point 1.
3) A way to modify a table in-place (that is more robust than our current one-change-at-a-time implementation).

Those are core features of the database system that it needs, unto itself, completely in isolation of the rest of Drupal.

Once the database layer is so-enhanced, then we can build other things on top of that as you mention. Such things include:
- Shipping a table definition object with a module (by whatever mechanism, class or YAML).
- Update hooks that contain various modify-in-place commands, as now.
- Some sort of magical "table structure diff" that takes 2 table objects and generates the appropriate modification command object. (This may get pushed down to the DB system itself, but it depends on the stuff above.)
- Caching of the table structure information. (Although if the FIG group ever defines a standardized caching interface, I am totally open to baking that into the DB layer directly.)

I fully support adding all of that functionality, but that is a phase 2 and must come after the changes above.

The most crucial change is the source of authority. Drupal currently assumes that the module-defined schema is definitive, and if the database itself doesn't match up then oh-well, things explode. That's backwards. Instead, the database itself should be definitive, and parts of Drupal that rely on database structure for their logic should get that information from the database, not from what the module developer claims the database is supposed to be.

There are 2 reasons for that. One, it's simply more correct conceptually. Two, Drupal's schema system requires a fully booted system: Hooks must work, caching must work, and there is, or was, a rather weird dependency on bootstrap phases due to module_list() being a knot of evil. (I don't know if that's been fixed yet in Drupal 8. I hope so.) I want to eliminate any and all such dependencies. If you can get a database connection, you should be able to get an up-to-date schema definition for a table without depending on any other part of Drupal whatsoever. That's good loose coupling, which is the direction Drupal has been, slowly and with much wailing and gnashing of teeth, moving. :-)

donquixote’s picture

Ok, I think we are not so far apart.
I always understood (and I think I mentioned that) that this issue is about your "phase 2", whereas the other issue is about the phase 1 stuff.
A different way to see it, is that this issue is where we have a private conversation, whereas the crowd is in the other issue :)
I have no objections with either of these viewpoints :)

I agree with your phase 1.
I still like my fluid syntax, but I agree we should do the low-level API first, and anyway it's all D9. Until then I will simply use my personal InjAPI bicycle, because I hate those huge arrays.

The most crucial change is the source of authority. Drupal currently assumes that the module-defined schema is definitive, and if the database itself doesn't match up then oh-well, things explode. That's backwards. Instead, the database itself should be definitive, and parts of Drupal that rely on database structure for their logic should get that information from the database, not from what the module developer claims the database is supposed to be.

Yep.
I just wonder if we should have a 3rd level in between, where we remember the schema information on every change. This might be a simple cache, but it could also remember some meta information that we cannot simply extract from the tables themselves, or simply, a more semantic and db-engine-independent representation of the schema.

Drupal's schema system requires a fully booted system [..] eliminate any and all such dependencies

Yep.
The authoritative description of the current state of the database can and should be available on early bootstrap.
The "how modules claim or want the schema to be like" can wait until much later in the request.

donquixote’s picture

Btw, isn't my post in #17 already quite close to that?

(I am missing some points there, but the main idea of separating current schema from the intended schema is there)

donquixote’s picture

Issue tags: -Schema API

Shipping a table definition object with a module (by whatever mechanism, class or YAML).

The "whatever mechanism" was the original intention of this issue.
I see this has to wait, but I would like to make a point, while we are at it.

I have seen some frameworks where you have a "one class per table" approach. This class contains one method to define the columns, and then some methods for CRUD operations.
I always found this approach kinda stupid. Even with code generation, you end up looking at lots of redundant code. Or, if the table contains only the definition method, then you have plenty of classes that do nothing.

I would agree with tables being objects, but if all they have is the definition of columns, then I'd rather see them as instances of a generic class, with a configuration argument.
Also I don't think that the CRUD operations, if any, need to live on the same object/class as the schema definitions.

----------

The "Shipping a table definition" is most relevant for modules that have a static schema, not depending on any other state information. Here the schema definition (by "whatever mechanism") is the developer's main point of schema control.
For modules with a dynamic schema, we may still have a (dynamic) table definition, but here it would be used more for testing than for anything else.

donquixote’s picture

Issue tags: +Schema API

(re-add tag)

donquixote’s picture

Issue summary: View changes

Answer the expected comment about memory.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

smustgrave’s picture

Status: Active » Postponed (maintainer needs more info)
Issue tags: +stale-issue-cleanup

Thank you for sharing your idea for improving Drupal.

We are working to decide if this proposal meets the Criteria for evaluating proposed changes. There hasn't been any discussion here for 8+ years which suggests that this has either been implemented or there is no community support. Your thoughts on this will allow a decision to be made.

Since we need more information to move forward with this issue, the status is now Postponed (maintainer needs more info). If we don't receive additional information to help with the issue, it may be closed after three months.

Thanks!

smustgrave’s picture

Status: Postponed (maintainer needs more info) » Closed (outdated)

3 months has past so closing out, but don't worry if still a valid task this can be re-opened by anyone.

Thanks!