object IdempotentInsert
Utilities for safely and idempotently inserting records to a datastore.
- Alphabetic
- By Inheritance
- IdempotentInsert
- AnyRef
- Any
- Hide All
- Show All
- Public
- Protected
Value Members
- final def !=(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- final def ##: Int
- Definition Classes
- AnyRef → Any
- final def ==(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- final def asInstanceOf[T0]: T0
- Definition Classes
- Any
- def clone(): AnyRef
- Attributes
- protected[lang]
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.CloneNotSupportedException]) @native() @IntrinsicCandidate()
- final def eq(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
- def equals(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef → Any
- final def getClass(): Class[_ <: AnyRef]
- Definition Classes
- AnyRef → Any
- Annotations
- @native() @IntrinsicCandidate()
- def hashCode(): Int
- Definition Classes
- AnyRef → Any
- Annotations
- @native() @IntrinsicCandidate()
- def insertIgnoringConflicts(storage: DbStorage, oracleIgnoreIndex: String, insertBuilder: => SQLActionBuilder): WriteOnly[Int]
Similar to insertVerifyingConflicts but without verifying that the existing data causing conflicts matches what we expect.
Similar to insertVerifyingConflicts but without verifying that the existing data causing conflicts matches what we expect. Should only be use where the possibilities of conflicts is limited to retries of our insert.
- def insertVerifyingConflicts[A](storage: DbStorage, oracleIgnoreIndex: String, insertBuilder: => SQLActionBuilder, select: ReadOnly[A], expectedRowsInserted: Int = 1)(existingCondition: (A) => Boolean, errorMessage: (A) => String)(implicit loggingContext: ErrorLoggingContext, executionContext: ExecutionContext): All[Unit]
Execute an insert to an append-only store.
Execute an insert to an append-only store. If less than
expectedRowsInserted
are found inserted perform a select and verify that the existing data is what we expect to existing in our store. If the existing data fails the provided check predicate a java.lang.IllegalStateException will be thrown as this indicates either a bug or a configuration error (such as a new node running with a database initialized by another node). If more rows are returned thanexpectedRowsInserted
a java.lang.IllegalStateException is also thrown as this indicates the insert query is doing something contrary to the developers expectations and is likely a bug.To use safely use the
oracleIgnoreIndex
field it **must** be suitable for directly interpolating as a raw string into the query without causing any risk of SQL injection. It is recommended that this value should be hard coded and never come from a value based on the environment or user input.This method will generate the
insert into
prefix for the insert statement, soinsertBuilder
needs to only contain the body of the insert statement excluding the typicalinsert into
prefix (this is so for oracle we can generate a suitable IGNORE_ROW_ON_DUPKEY_INDEX hint.Typical usage will look like:
insertVerifyingConflicts( logger, storage, "my_table ( pk_col )", // callers MUST ensure this is safe to interpolate directly into the sql query sql"my_table (pk_col, name) values ($$id, $$name)", // note the missing `insert into` prefix or any `on conflict` postfix. this will be generated appropriately for the target db. sql"select name from my_table where pk_col = $$id".as[String].head // query values to check successfully exist in the target store. )( _ == name, existingName => s"Expected row $$id to have name $$name but found existing name $$existingName" )
Note that no transaction is started within this method and therefore changes could become visible between the insert and the select that we may then perform. However as the usage of this is intended for append-only stores separate modifications of this data is not expected.
Regarding performance the select statement will only be executed if the returned inserted row count is different from the
expectedRowsInserted
value. We anticipate this happening potentially due to crashes or retries due to connectivity issues, and should be rare during normal healthy operation. So typically only the insert should be run. - final def isInstanceOf[T0]: Boolean
- Definition Classes
- Any
- final def ne(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
- final def notify(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native() @IntrinsicCandidate()
- final def notifyAll(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native() @IntrinsicCandidate()
- final def synchronized[T0](arg0: => T0): T0
- Definition Classes
- AnyRef
- def toString(): String
- Definition Classes
- AnyRef → Any
- final def wait(arg0: Long, arg1: Int): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException])
- final def wait(arg0: Long): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException]) @native()
- final def wait(): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException])