Skip to content
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

Atomic commits #63

Open
christiangarsia opened this issue Oct 3, 2019 · 6 comments
Open

Atomic commits #63

christiangarsia opened this issue Oct 3, 2019 · 6 comments

Comments

@christiangarsia
Copy link
Contributor

Can I create atomic commits involving different tables using Maphper? If an insert fails, I want everything to roll back. I want to use SQLite3.

@TRPB
Copy link
Member

TRPB commented Oct 3, 2019

I'm not sure there would be a particularly clean way to implement this because however you do it, it's action at a distance (By design, it's changing the database).

Assuming transactions work the same way they do in MySQL, you could do this:

$blogSource = new \Maphper\DataSource\Database($pdo, 'blog', 'id');

$pdo->query('START TRANSACTION');

// Do something with your various mappers

$pdo->query('COMMIT'); //or ROLLBACK

While this could be done in the Database class, this would assume that all databases support transactions and break the principle of least surprise:

$blogSource->beginTransaction();
//...
$blogSource->commit();

Would affect all \Maphper\DataSource\Database instances because it's configuring the underlying database connection.

I'm happy to take suggestions, but because this is done at a database level, not a table level, it doesn't really fit neatly into what Maphper is doing.

@TRPB
Copy link
Member

TRPB commented Oct 6, 2019

Thinking about this a little more, Maphper could infer transactions when performing multiple inserts at the same time.

$user = new \stdclass;

$user->name = 'Foo';

//Address is a relationship
$user->address = new \stdclass;

$user->address->address1 = '123 fake street';


//Perform a nested save to `user` and `address` tables
$users[] = $user;

It would be limited to this single use case: Inserting multiple records at the same time using the defined relationships.

Would that work for what you're doing?

Having said that, I wouldn't recommend getting to the stage where an insert fails. Maphper performs insert or update and assumes that the data is saved. In edit mode, it automatically updates the table to fit the data supplied.

I'd recommend making sure the data is valid before sending it to the database. See also: https://r.je/4-reasons-to-avoid-foreign-key-constraints-database-logic

@christiangarsia
Copy link
Contributor Author

christiangarsia commented Oct 6, 2019

Thanks. That is exactly what I am looking for, although I would need to go one level deeper (eg. address also has an object and a third table would be required), would that still be possible?
I understand what you mean about validating the data before, but I’m thinking about a scenario where the database connection would be lost (eg. power loss) half way and I would want to keep my tables consistent.

@TRPB
Copy link
Member

TRPB commented Oct 6, 2019

Yes, it would work for any depth.

I'll try to get a patch together over the next few days. The hard part is keeping track of whether a transaction has already been started which looks like it's poorly supported on both MySQL and SQLite.

@christiangarsia
Copy link
Contributor Author

Yes, it would work for any depth.

I'll try to get a patch together over the next few days. The hard part is keeping track of whether a transaction has already been started which looks like it's poorly supported on both MySQL and SQLite.

Any update on this request? Thanks.

@pwFoo
Copy link

pwFoo commented May 31, 2020

Would be a nice optional feature I think.

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

No branches or pull requests

3 participants