The motivation of this is to create a version column. This column will be used for concurrency control in EFCore. In other words, we can use this version column to check concurrency when loading content into Directus via in house code.
create table `test_table` (
`id` int(15) unsigned not null auto_increment,
`name` varchar(200) default null,
`version` datetime(6) default current_timestamp(6) on update current_timestamp(6),
primary key (`id`)
) ENGINE = InnoDB auto_increment = 3 default CHARSET = utf8mb4;
update
directus_fields
set
type = 'datetime_updated',
interface = 'datetime-updated',
options = '[]',
hidden_detail = 1,
hidden_browse = 1
where
field = 'version';
Directus creates a record in test_table with version column filled in with the current DateTime
{
"class": "Directus\\Validator\\Exception\\InvalidRequestException",
"code": 4,
"file": "/shared/httpd/cms/src/core/Directus/Services/AbstractService.php",
"line": 186,
"message": "version: This value is not a valid datetime."
}
See: https://github.com/directus/api/issues/531 for a similar bug report
EDIT: Adding mysql datetime precision to create table sql
I think I've tracked down offending function:
I think the fix is as simple as the following check for the $value.
However, I'm not sure the implications of this change without doing a much deeper dive. (not to mention my php experience is < 3 weeks)
public function validate($value, Constraint $constraint)
{
if ($value == "current_timestamp()") {
return;
}
if ($constraint instanceof DateTime && is_iso8601_datetime($value)) {
$constraint->format = get_iso8601_format($value);
}
parent::validate($value, $constraint);
}
I found a not perfect work around.
For columns only used for concurrency checks, you can work around by setting the default value to some arbitrary datetime in the past. For example, the unix epoch. If you're not using this for concurrency, then this remains a bug as you probably care about the actual current time.
If creating a new record from within Directus, the version column will correctly be filled in with the current_timestamp(). If creating a record from outside of Directus, the version column will be filled in with your arbitrary datetime.
No matter the source of the update for a currently existing record, the on update statement will execute.
create table `test_table` (
`id` int(15) unsigned not null auto_increment,
`name` varchar(200) default null,
`version` datetime default '1970-01-01 00:00:01' on update current_timestamp(6),
primary key (`id`)
) ENGINE = InnoDB auto_increment = 3 default CHARSET = utf8mb4;
Another update:
The fix isn't as simple as this one I posted above. My proposed fix only works for fields that are configured for the datetime-updated interface.
If using a regular datetime interface, this workaround fails. Somewhere down the pipeline some validation is being done and makes the save action fail. I guess there's a difference in validation for the two interfaces? See javascript error returned after saving:
{
"error": {
"code": null,
"message": "DateTime::__construct(): Failed to parse time string (current_timestamp()) at position 0 (c): The timezone could not be found in the database",
"class": "Exception",
"file": "/shared/httpd/hollywood-cms/src/core/Directus/Util/DateTimeUtils.php",
"line": 87
}
}
Phinx has already the issue with current_timestamp. You can check here
@bjgajjar
Not sure what Phinx has to do with this. I created tables using raw sql, not using Phinx migrations.
I created tables using raw sql, not using Phinx migrations.
System use the phinx for DB iterations. When you are trying to manage the fields, the system will automatically use the phinx itself.
Don't worry. I will try to find some work around for this.
Ah I see. Tyvm for the clarification.
@benhaynes - We have a dependency on another package for this. Can you please guide me on what should the next step for this issue? Should we consider it a known issue or should we try to resolve it?
I would direct these technical questions to @rijkvanzanten and/or @WoLfulus ... this is outside my expertise.
It sounds like the API is returning the string current_timestamp(6) as default value from the API at which point the app will try to pass that on as the value for the datetime interface, which throws the error. In JS, current_timestamp is not a valid datetime string value.
We have two potential solutions:
Check for current_timestamp in the client side and render "Current Date" as placeholder in the datefield
Has the problem that the current timestamp will change from the time the information is requested and the time the field is saved, which causes the value that's shown in the interface to be off by a couple seconds to minutes. 2. has the problem that there might be more of these implementation specific default values coming up that aren't covered. Once we support other sql based databases, this will get very annoying to maintain on the front-end