Ecto - format of returned value during error on update_all - phoenix-framework

When using Ecto's update_all to update all matching records, what is the format of the returned values in an error situation? The documentation is a little vague about what to expect back - 'It returns a tuple containing the number of entries and any returned result as second element.'
For example, let's say there are 10 matching records and for whatever reason, the update action fails on 2 of those records. My assumption is that the returned value would look like this:
{8, [{:error, error info}, {:error, error info}]}
Is that correct? Would the errors come back as a list of tuples?

No, if the UPDATE query fails, Repo.update_all throws an error. No changes are actually saved in the database if this happens.
The list in the second element of the returned tuple is the data you've asked the query to return using the RETURNING clause, e.g. query |> Repo.update_all([], returning: [:id]) will return the updated structs with just the id field populated and returning: true will return structs with all the fields populated.
Here's an example of an error occurring in one record of an update query:
iex(1)> from(p in Post, select: p.id) |> Repo.all
[debug] QUERY OK source="posts" db=1.1ms queue=0.1ms
SELECT p0."id" FROM "posts" AS p0 []
[1, 2, 3]
iex(2)> from(p in Post, where: p.id in [2, 3], update: [set: [id: fragment("CASE WHEN ? = 3 THEN 1 ELSE ? END", p.id, p.id)]]) |> Repo.update_all([])
** (Postgrex.Error) ERROR 23505 (unique_violation): duplicate key value violates unique constraint "posts_pkey"
table: posts
constraint: posts_pkey
Key (id)=(1) already exists.
[debug] QUERY ERROR source="posts" db=4.8ms
UPDATE "posts" AS p0 SET "id" = CASE WHEN p0."id" = 3 THEN 1 ELSE p0."id" END WHERE (p0."id" IN (2,3)) []
(ecto) lib/ecto/adapters/sql.ex:436: Ecto.Adapters.SQL.execute_and_cache/7

Related

Bot Composer - Join list from Luis entity

Bot Framework Composer v1.4.1
I have a bot connected to Luis, which returns a list entity that I need to operate with that data.
The entity that I get is a list of categories, and I need to concatenate all the elements of that list into a string
"entities": {
"CategoryList": [
[
"sub-13-Imprimante",
"12-materiels"
]
]
}
The expected result is
"sub-13-Imprimante,12-materiels"
I have tried different options but none concatenate the result as expected.
#CategoryList //This only assign first element of the array ("sub-13-Imprimante")
join(#CategoryList, ',') //Throw error
The error obtained in the join statement is:
System.InvalidOperationException: 'NewTicket.fr-fr.lg:#CategoryList evaluates to sub-13-Imprimante which is not a list. [SendActivity_D8EXfc] Error occurred when evaluating '- ${join(#CategoryList, ',')}'.
It would seem that when calling #CategoryList, it already returns the first item, instead of the entire list.
How could I do to obtain all the values of the array concatenated in a string?
#CategoryList will return the first and only the first value found for the entity. ##CategoryList will return the entire thing. So, what you need is join(##CategoryList, ',')
See more info here:
https://learn.microsoft.com/en-us/composer/concept-memory?tabs=v2x#memory-shorthand-notations

$operations = Operation::findOrFail(2)->get(); return 6 results

I'm trying to get the operation that as PK id = 2
$operations = Operation::findOrFail(2)->get();
This line should do the trick, but I get all my 6 operations as result...
Off course, my other 5 has ID value from 1 to 6, they doesn't match.
I checked Operation is a model with no custom config, and Operation table has been created by migration and has ID as PK...
Off course, I could change it with another eloquent query, but this should work and I would love to know why it is failing.
What am I missing ?
remove ->get() it will should be
$operations = Operation::with('meters')->findOrFail(2);
get() gives you a collection which is all data of Operation to get single instace you should remove get()

Groovy Sql rows

Hello I am trying to get rows using Groovy Sql connection but it returns me records as a List inside a List. The following:
Sql sql = new Sql(dataSource)
List<GroovyRowResult> row = sql.rows('select * from user where username=:userName and password=:password, [userName:'groovy',password:'123'])
returns the result as [[return record as map]]
Any one help me to figure out why the result is a List inside a List. How will I get it as a single level List using the rows method?
Your results are coming back as a list of maps, not a list of lists. Look at the ':' and ',' chars in the inner part. You can use standard groovy extraction of values from these.
In your case, it looks like you're using a primary key search, so will only return one result, so use firstRow in this case, so that you don't have to extract the single map result from the list.
See the documentation for the groovy Sql class for examples.
In the more general case where you are returning multiple rows, then your data probably looks like this:
[[username:"foo", password:"foopass"], [username:"bar", password:"barpass"]]
Assuming the line:
def results = sql.rows('select * from user')
You can then do things like spread operators:
assert results.username == ["foo", "bar"]
assert results.password == ["foopass", "barpass"]
or iterate over the results
results.each { println it.username }
==> foo
==> bar
or use any of the many Collection functions
println results.collect { "${it.username} -> ${it.password}" }
==> [ "foo -> foopass", "bar -> barpass" ]
I think your main issue was not recognising a single map entry in a list.
It doesn't return a List inside a List, it returns a List of Map with each map containing the columns selected from your select.
So if you want all of the usernames selected (as a List), you can just do:
def usernames = row.username
If you just want a single row, you can do:
GroovyRowResult row = sql.firstRow('select * from user where username=:userName and password=:password, [userName:'groovy',password:'123'])
And then this will effectively just be a map with each key being the field name selected, and each value being the value of the first row of each field

Can I FlexMock a method to raise an exception on the first call, then return a valid object on the second call?

I'm working on some Ruby code that needs to create primary keys on existing MySQL database tables. It needs to detect and fix duplicates to allow index creation to succeed, with the following algorithm:
# 1. Query
ALTER TABLE foo ADD PRIMARY KEY (id)
# 2. Handle exception:
Duplicate entry '3761290' for key 'PRIMARY' (Mysql::Error)
# 3. Query:
SELECT COUNT(1) FROM TABLE foo WHERE id = 3761290
# 4. (Assuming 5 rows were returned from the previous query) Query:
DELETE FROM TABLE foo WHERE id = 3761290 LIMIT 4 OFFSET 1
# 5. retry ALTER TABLE query
The test looks something like this:
def test_create_primary_key
table = 'foo'
db = flexmock
db.should_receive(:prepare).
with("ALTER TABLE #{table} ADD PRIMARY KEY (id)").
twice.
and_raise(Mysql::Error, "Duplicate entry '3761290' for key 'PRIMARY'")
db.should_receive(:prepare).
with("SELECT COUNT(1) FROM #{table} WHERE id = ?").
once.
and_return(MockStatement.new [ [5] ])
db.should_receive(:prepare).
with("DELETE FROM #{table} WHERE id = ? LIMIT 4 OFFSET 1").
once.
and_return(MockStatement.new [ [5] ])
indexer = Indexer.new :database_handle => db
indexer.create_indexes table
end
The problem is that the code will run in an infinite loop (unless it has a max retries condition, which it may well do), since it will continue to get an exception from the FlexMock'd db.
Ideally, the mock should be able to raise an exception the first time, then return a valid statement handle the second time. The block form of #with might work here, but I'd like to do it in a clean way if at all possible.
Any ideas?
I forgot that since Ruby (generally) conforms to The Principle of Least Astonishment, one should just try what makes sense and see what happens:
def test_yield_then_return
mock = flexmock
flexmock(mock).should_receive(:foo).
with(:bar).
and_raise(RuntimeError).
and_return(true)
assert_raises(RuntimeError) { mock.foo :bar }
assert mock.foo(:bar)
end
Does what it says on the tin. :)

Is this a LINQ lazy loading problem?

Something very strange is happening in my program:
I make this query agt.DefaultNr == 1 on a collection and get 3 items as Result:
IEnumerable<Agent> favAgents =
from agt in builtAgents where agt.DefaultNr == 1 select agt;
For every item I set the DefaultNr = 0
foreach (Agent noFavAgt in favAgents)
{
noFavAgt.DefaultNr = 0;
}
I do another query but for some reason my favAgents collection is empty now!
IEnumerable<Agent> smallAgents = (from agt in favAgents
where agt.tempResultCount < 30
orderby agt.tempResultCount descending
select agt);
What is going on here?
Is this a LINQ lazy loading problem?
Looks like there will be some kind of re-query after I set all items = 0 because I my collection is empty!
This is not lazy loading, it's deferred execution. When you define your initial enumerable, you're defining a query, not a collection. You're correct that it's performing a requery; every time you iterate over favAgents, it will execute the query that you defined. If you want to create a list based off of that query that doesn't change, add ToList().
var favAgents =
(from agt in builtAgents where agt.DefaultNr == 1 select agt).ToList();
Doing this will create a list in memory and cache the results of the query at that point in time.
Yes, your favAgents collection will be empty now - you've "turned off" the bit in each element of it that made it match the query! If you iterate over favAgents twice, it will execute the query twice. favAgents represents the query itself, not the results.
If you want to preserve one particular set of results, use ToList or something similar:
favAgents = favAgents.ToList();
That will materialize the query - perform it once and then remember the results in a list, basically. ToArray would have the same effect, but store the results in an array instead.

Resources