`persistenceConflictPolicy` per query?

Hi,

I'm in the situation where I sometimes want the conflict policy to be .abort and sometimes .ignore. I currently solve that by using:

Aperture.persistenceConflictPolicy = PersistenceConflictPolicy(insert: .ignore, update: .abort)
defer { Aperture.persistenceConflictPolicy = PersistenceConflictPolicy(insert: .abort, update: .abort) }

Unfortunately, this doesn't play very nice with multi-threading, where another thread might want the other conflict policy.
Is there a way to set the policy per query?
Otherwise it seems I should always set the policy to ignore and after every insert query the DB to get the inserted row.

Thanks in advance.

Kind regards,

Remco Poelstra

Hello @remcopoelstra,

There is no way to choose the policy for each individual request, because I did not foresee any use case. But I hear the feature request.

(Would you please explain in a few sentences what is your use case?)

Meanwhile, you have no multi-threading issue as long as you change the static policy inside a database access method (such as DatabaseQueue.write { db in ... }): those all run in a serialized DispatchQueue.

Hi,

Thanks for your response.
I've a document based application with each document having a database, so your suggestion doesn't work for me unfortunately.

Most of the time I just know that each row will be unique so I use the .abort policy to get easy code (I often need the ID shortly after inserting the row). (Like when importing data into the database).
Sometimes I'm not sure whether the row already exists, but I then also don't care as long as one does in the end. (Like when copy-pasting elements in the document.) So I use the .ignore policy and always perform an insert. I then fetch the resulting ID. This requires more code, so I only use the .ignore policy as little as possible.

On what timeframe do you expect you can add this feature? I can live with this issue for months just fine. If it will take longer, I'll come up with another solution.

Thanks!

Kind regards,

Remco Poelstra

Ha, I see. Yes, since two databases may run concurrently, you can't safely mutate the shared policy. Thanks for reminding this.

On what timeframe do you expect you can add this feature?

:rofl:

More seriously, the problem is that all persistence methods are eventually routed to the fundamental insert(_:)and update(_:columns:) methods. Those can be overridden by the user. And they do not accept a conflict policy as an argument.

So this feature is a breaking change, and it won't exist until GRDB 6, and it's not really a matter of timeframe, I'm sorry.

When you describe your use case, I think I understand why you can't always use .ignore. It is because insertions performed with the ignore policy makes the latest inserted row id unreliable (this is, at the core, an SQLite limitation). When your app needs those inserted row ids, you really want to use the regular abort policy.

I hope I interpret correctly.

May I suggest an alternative technique? Since you prefer to use the .ignore policy as little as possible, keep the default .abort policy, and ignore the insertion errors just when you want to ignore them:

do {
    try aperture.insert(db)
} catch DatabaseError.SQLITE_CONSTRAINT { }

Another technique is to fork GRDB and add the needed feature, of course. Be ready to submit a pull request when you see that GRDB 6 is scheduled!

Now it's my turn: :rofl:
This is way above my capabilities...

I'll go with your suggestion to catch the insertion errors when I don't care about them.

Kind regards,

Remco Poelstra

I hope this will work fine. Please tell if anything goes wrong: we'll find a workaround then, at the lowest possible expense.

This is way above my capabilities...

It's difficult to tell until you try ;-)

This works like a charm. Thanks.

You're absolutely right. It's at least way out of my comfort zone :slight_smile:

1 Like