Browse Source

server: Batch insert for inputs/outputs on TransactionPostgresDAO

prometheus-integration
Alexis Hernandez 6 years ago
parent
commit
81535991a7
  1. 118
      server/app/com/xsn/explorer/data/anorm/dao/TransactionPostgresDAO.scala

118
server/app/com/xsn/explorer/data/anorm/dao/TransactionPostgresDAO.scala

@ -20,8 +20,8 @@ class TransactionPostgresDAO @Inject() (fieldOrderingSQLInterpreter: FieldOrderi
def upsert(index: Int, transaction: Transaction)(implicit conn: Connection): Option[Transaction] = { def upsert(index: Int, transaction: Transaction)(implicit conn: Connection): Option[Transaction] = {
for { for {
partialTx <- upsertTransaction(index, transaction) partialTx <- upsertTransaction(index, transaction)
inputs <- upsertInputs(transaction.id, transaction.inputs) inputs <- insertInputs(transaction.id, transaction.inputs)
outputs <- upsertOutputs(transaction.id, transaction.outputs) outputs <- insertOutputs(transaction.id, transaction.outputs)
_ <- spend(transaction.id, inputs) _ <- spend(transaction.id, inputs)
_ = insertDetails(transaction) _ = insertDetails(transaction)
} yield partialTx.copy(inputs = inputs, outputs = outputs) } yield partialTx.copy(inputs = inputs, outputs = outputs)
@ -347,94 +347,84 @@ class TransactionPostgresDAO @Inject() (fieldOrderingSQLInterpreter: FieldOrderi
).as(parseTransaction.singleOpt).flatten ).as(parseTransaction.singleOpt).flatten
} }
private def upsertInputs( private def insertInputs(
transactionId: TransactionId, transactionId: TransactionId,
inputs: List[Transaction.Input])( inputs: List[Transaction.Input])(
implicit conn: Connection): Option[List[Transaction.Input]] = { implicit conn: Connection): Option[List[Transaction.Input]] = {
val result = inputs.map { input => inputs match {
upsertInput(transactionId, input) case Nil => Some(inputs)
}
if (result.forall(_.isDefined)) { case _ =>
Some(result.flatten) val params = inputs.map { input =>
} else { List(
None 'txid -> transactionId.string: NamedParameter,
} 'index -> input.index: NamedParameter,
'from_txid -> input.fromTxid.string: NamedParameter,
'from_output_index -> input.fromOutputIndex: NamedParameter,
'value -> input.value: NamedParameter,
'address -> input.address.string: NamedParameter)
} }
private def upsertInput( val batch = BatchSql(
transactionId: TransactionId,
input: Transaction.Input)(
implicit conn: Connection): Option[Transaction.Input] = {
SQL(
""" """
|INSERT INTO transaction_inputs |INSERT INTO transaction_inputs
| (txid, index, from_txid, from_output_index, value, address) | (txid, index, from_txid, from_output_index, value, address)
|VALUES |VALUES
| ({txid}, {index}, {from_txid}, {from_output_index}, {value}, {address}) | ({txid}, {index}, {from_txid}, {from_output_index}, {value}, {address})
|ON CONFLICT (txid, index) DO UPDATE """.stripMargin,
| SET value = EXCLUDED.value, params.head,
| address = EXCLUDED.address, params.tail: _*
| from_txid = EXCLUDED.from_txid, )
| from_output_index = EXCLUDED.from_output_index
|RETURNING txid, index, from_txid, from_output_index, value, address
""".stripMargin
).on(
'txid -> transactionId.string,
'index -> input.index,
'from_txid -> input.fromTxid.string,
'from_output_index -> input.fromOutputIndex,
'value -> input.value,
'address -> input.address.string
).as(parseTransactionInput.singleOpt).flatten
}
private def upsertOutputs(
transactionId: TransactionId,
outputs: List[Transaction.Output])(
implicit conn: Connection): Option[List[Transaction.Output]] = {
val result = outputs.map { output => val success = batch.execute().forall(_ == 1)
upsertOutput(transactionId, output)
}
if (result.forall(_.isDefined)) { if (success) {
Some(result.flatten) Some(inputs)
} else { } else {
None None
} }
} }
}
private def upsertOutput( private def insertOutputs(
transactionId: TransactionId, transactionId: TransactionId,
output: Transaction.Output)( outputs: List[Transaction.Output])(
implicit conn: Connection): Option[Transaction.Output] = { implicit conn: Connection): Option[List[Transaction.Output]] = {
SQL( outputs match {
case Nil => Some(outputs)
case _ =>
val params = outputs.map { output =>
List(
'txid -> transactionId.string: NamedParameter,
'index -> output.index: NamedParameter,
'value -> output.value: NamedParameter,
'address -> output.address.string: NamedParameter,
'hex_script -> output.script.string: NamedParameter,
'tpos_owner_address -> output.tposOwnerAddress.map(_.string): NamedParameter,
'tpos_merchant_address -> output.tposMerchantAddress.map(_.string): NamedParameter)
}
val batch = BatchSql(
""" """
|INSERT INTO transaction_outputs |INSERT INTO transaction_outputs
| (txid, index, value, address, hex_script, tpos_owner_address, tpos_merchant_address) | (txid, index, value, address, hex_script, tpos_owner_address, tpos_merchant_address)
|VALUES |VALUES
| ({txid}, {index}, {value}, {address}, {hex_script}, {tpos_owner_address}, {tpos_merchant_address}) | ({txid}, {index}, {value}, {address}, {hex_script}, {tpos_owner_address}, {tpos_merchant_address})
|ON CONFLICT (txid, index) DO UPDATE """.stripMargin,
| SET value = EXCLUDED.value, params.head,
| address = EXCLUDED.address, params.tail: _*
| hex_script = EXCLUDED.hex_script, )
| tpos_owner_address = EXCLUDED.tpos_owner_address,
| tpos_merchant_address = EXCLUDED.tpos_merchant_address val success = batch.execute().forall(_ == 1)
|RETURNING txid, index, value, address, hex_script, tpos_owner_address, tpos_merchant_address
""".stripMargin if (success) {
).on( Some(outputs)
'txid -> transactionId.string, } else {
'index -> output.index, None
'value -> output.value, }
'address -> output.address.string, }
'hex_script -> output.script.string,
'tpos_owner_address -> output.tposOwnerAddress.map(_.string),
'tpos_merchant_address -> output.tposMerchantAddress.map(_.string)
).as(parseTransactionOutput.singleOpt).flatten
} }
private def deleteInputs(txid: TransactionId)(implicit conn: Connection): List[Transaction.Input] = { private def deleteInputs(txid: TransactionId)(implicit conn: Connection): List[Transaction.Input] = {

Loading…
Cancel
Save