How to get Corda transaction time? - corda

I am using the following to get the transaction timestamp:
val outputStateRef = StateRef(ledgerTx.id, 0)
val queryCriteria = QueryCriteria.VaultQueryCriteria(stateRefs = listOf(outputStateRef))
val results = serviceHub.vaultService.queryBy<ContractState>(queryCriteria)
val recordedTime = results.statesMetadata.singleOrNull()?.recordedTime
The problem is the transaction time is not always returned, sometimes null is returned for the timestamp.
Why is this happening and how can I ensure the timestamp is always returned?

results is Vault.Page<ContractState> which contains the following variables:
/**
* Returned in queries [VaultService.queryBy] and [VaultService.trackBy].
* A Page contains:
* 1) a [List] of actual [StateAndRef] requested by the specified [QueryCriteria] to a maximum of [MAX_PAGE_SIZE].
* 2) a [List] of associated [Vault.StateMetadata], one per [StateAndRef] result.
* 3) a total number of states that met the given [QueryCriteria] if a [PageSpecification] was provided,
* otherwise it defaults to -1.
* 4) Status types used in this query: [StateStatus.UNCONSUMED], [StateStatus.CONSUMED], [StateStatus.ALL].
* 5) Other results as a [List] of any type (eg. aggregate function results with/without group by).
*
* Note: currently otherResults are used only for Aggregate Functions (in which case, the states and statesMetadata
* results will be empty).
*/
As it looks from your code, if result page contains multiple StateAndRef, the method code singleOrNull()? will actually return null.
This is my guess based on available codes, please share more information if this wasnt the cause of the issue.

I would add your own timestamp to the state and record it in the flow.
Or, you can add a Time-Window to the transaction (https://docs.corda.net/api-transactions.html#time-windows). I believe this also ensures that the statesMetadata.recordedTime will not be null.

Related

Database row len() can be print, but this value can’t be shown in tkinter entry

I can”t understood, why I can print the value of rows, but not populate this to a tkinter entry.
My code:
cursor.execute(‘SELECT * FROM contacts;’)
print(‘row in table contacts:’,len(cursor.fetchall())) # prints 104
self.no_count.set(len(cursor.fetchall())) # populate 0
Any hint?
You should store the fetched data inside a variable and then access it through the variable. This is because a cursor is like a python generator, and once you use cursor.fetchall() the results will no longer contain the result again. So go for something like:
cursor.execute('SELECT * FROM contacts;')
data = cursor.fetchall() # Store in variable
print(f'row in table contacts: {len(data)}') # Used f strings instead of comma(can be ignored)
self.no_count.set(len(data))
Or you could also go for the inefficient way of repeating your query each time, like:
cursor.execute(‘SELECT * FROM contacts;’)
print(f‘row in table contacts: {len(cursor.fetchall())}')
cursor.execute(‘SELECT * FROM contacts;’) # Repeat the query
self.no_count.set(len(cursor.fetchall())) # Fetch again

TopK function over Distributed Engine In clickhouse returns only 10 records

I'm running the following query
select topK(30)(Country) from distributed_table
note: distributed_table's engine is Distributed.
and even though there are over 100 possible "country" values, the query returns only 10.
Also, when I run it on local table , I'm getting more than 10 results.
Have I missed out some crucial configuration?
It looks like the problem occurs when intermediate results from shards are combined to the final result.
Let's check the results from each shard (will use distributed_group_by_no_merge-setting to disable the merging of intermediate results from each shard):
select any(_shard_num), topK(30)(Country)
from distributed_table
SETTINGS distributed_group_by_no_merge = 1
On each shard, the topK-function works correctly so as a workaround you can combine all intermediate results manually:
SELECT arrayDistinct(
arrayMap(x -> x.1,
/* sort values by frequency */
arraySort(x -> x.2,
/* converts an array of arrays to a flat array */
flatten(
/* group results from shards to one array */
groupArray(
/* assign each value the index number */
arrayMap((x, index) -> (x, index), shard_result, arrayEnumerate(shard_result))))))) ordered_value
FROM (
select topK(30)(Country) AS shard_result
from distributed_table
SETTINGS distributed_group_by_no_merge = 1)

Symfony4: Validate DateIntervalType

I am currently stuck on a probably very simple question.
How do I validate my DateIntervalType to be != 0 - meaning atleast something has been selected.
And how do I set a minimum/maximum: for example minimum interval of 1 day.
Background: I want to send an email every X years/months/days depending on the user select - an interval of 0 would mean permanent email sending, which I do not want.
Sadly I did not find anything helpful yet. Also tried integer assertations like #Assert\GratherThan etc. but that does not work.
Thanks in advance
Solution: Thanks to #Arleigh Hix for putting me on the right direction.
I solved my problem with following solution:
/**
* #Assert\Expression("this.checkInterval()")
*/
private $interval;
public function checkInterval() {
return $this->getTimestamp()->add($this->getInterval()) > $this->getTimestamp(); //getTimestamp() returns a DateTime
}
So basically just add the interval to any date and compare the new date to the initial date. With this way you can also get the difference in seconds and compare for min max values.
Better practise is probably to create a custom validator which will be my next step.
It looks you should be able to use an Expression constraint Maybe like this (I'm not sure about syntax for constructing the \DateInterval in the annotation)
/**
* #Assert\Expression(
* "value >= minimum",
* values = { "minimum": new \DateInterval('P1D') }
* )
*/
$dateIntervalField;
Alternatively, you should be able to set your minimum interval to an entity property and then compare value to that.
public function __construct()
{
$this->minInterval = new \DateInterval('P1D');
}
/**
* #Assert\GreaterThanOrEqual(
* value = this.minInterval
* )
*/
$dateIntervalField;

LINQ: Get all members with LAST order failed

I'm learning LINQ, and I'm trying to figure out how to get all members with the last order failed (each member can have many orders). For efficiency reasons I'd like to do it all in LINQ before putting it into a list, if possible.
So far I believe this is the right way to get all the members with a failed order which joined recently (cutoffDate is current date -10 days).
var failedOrders =
from m in context.Members
from o in context.Orders
where m.DateJoined > cutoffDate
where o.Status == Failed
select m;
I expect I need to use Last or LastOrDefault, or possibly I need to use
orderby o.OrderNumber descending
and then get the First or FirstOrDefault as suggested in this stackoverflow answer.
Note that I want to look at ONLY the last order for a given member and see if that has failed (NOT just find last failed order).
Normally you would write something like:
var failedOrders = from m in context.Members
where m.DateJoined > cutoffDate
select new
{
Member = m,
LastOrder = m.Orders.OrderByDescending(x => x.OrderNumber).FirstOrDefault()
} into mlo
// no need for null checks here, because the query is done db-side
where mlo.LastOrder.Status == Failed
select mlo; // or select mlo.Member to have only the member
This if there is a Members.Orders relationship

Correct parameter binding for SELECT WHERE .. LIKE using fmdb?

First time user of fmdb here, trying to start off doing things correctly. I have a simple single table that I wish to perform a SELECT WHERE .. LIKE query on and after trying several of the documented approaches, I can't get any to yield the correct results.
e.g.
// 'filter' is an NSString * containing a fragment of
// text that we want in the 'track' column
NSDictionary *params =
[NSDictionary dictionaryWithObjectsAndKeys:filter, #"filter", nil];
FMResultSet *results =
[db executeQuery:#"SELECT * FROM items WHERE track LIKE '%:filter%' ORDER BY linkNum;"
withParameterDictionary:params];
Or
results = [db executeQuery:#"SELECT * FROM items WHERE track LIKE '%?%' ORDER BY linkNum;", filter];
Or
results = [db executeQuery:#"SELECT * FROM items WHERE track LIKE '%?%' ORDER BY linkNum;" withArgumentsInArray:#[filter]];
I've stepped through and all methods converge in the fmdb method:
- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args
Depending on the approach, and therefore which params are nil, it then either calls sqlite3_bind_parameter_count(pStmt), which always returns zero, or, for the dictionary case, calls sqlite3_bind_parameter_index(..), which also returns zero, so the parameter doesn't get slotted into the LIKE and then the resultSet from the query is wrong.
I know that this is absolutely the wrong way to do it (SQL injection), but it's the only way I've managed to have my LIKE honoured:
NSString *queryString = [NSString stringWithFormat:#"SELECT * FROM items WHERE track LIKE '%%%#%%' ORDER BY linkNum;", filter];
results = [db executeQuery:queryString];
(I've also tried all permutations but with escaped double-quotes in place of the single quotes shown here)
Update:
I've also tried fmdb's own …WithFormat variant, which should provide convenience and protection from injection:
[db executeQueryWithFormat:#"SELECT * FROM items WHERE track LIKE '%%%#%%' ORDER BY linkNum;", filter];
Again, stepping into the debugger I can see that the LIKE gets transformed from this:
… LIKE '%%%#%%' ORDER BY linkNum;
To this:
… LIKE '%%?%' ORDER BY linkNum;
… which also goes on to return zero from sqlite3_bind_parameter_count(), where I would expect a positive value equal to "the index of the largest (rightmost) parameter." (from the sqlite docs)
The error was to include any quotes at all:
[db executeQuery:#"SELECT * FROM items WHERE track LIKE ? ORDER BY linkNum;", filter];
… and the % is now in the filter variable, rather than in the query.

Resources