Rails Query Active Record By Pairs OR'ed - ruby-on-rails

I have an API that looks like...
get(not_unique_id:, pairs: [])
...where pairs can look like [{ foo: 1, bar: 'a' }, { foo: 2, bar: 'b' }] and I want to write a query that will find all entries for the given non unique id, filtered by the pairs, i.e. ...
Thing.where(not_unique_id: not_unique_id)
# need help here -> .where("(foo = #{pairs.first[:foo]} AND bar = #{pairs.first[:bar]}) OR (foo = #{pairs.second[:foo]} AND bar = #{pairs.second[:bar]}) OR ...")
.map # or whatever else I want to do
I need a way to perform this foo AND bar comparison for each entry in my input pairs, OR'ed together to return all results that are have the not unique ID AND one of the pairs' values.

You can use or to chain together multiple where clauses with ORs:
Record.where(a: 'b').or(Record.where(c: 'd')).to_sql
# => select * from records where (a = 'b' OR c = 'd')
Using this and your array of conditions, you can provide a starting "seed" of Record.all to a reduce call and chain multiple successive conditions by oring them onto the scope:
conditions = [{ foo: 1, bar: 'a' }, { foo: 2, bar: 'b' }]
records = conditions.inject(Record.all) do |scope, condition|
scope.or(Record.where(condition))
end

Related

How do I sort a simple Lua table alphabetically?

I have already seen many threads with examples of how to do this, the problem is, I still can't do it.
All the examples have tables with extra data. For example somethings like this
lines = {
luaH_set = 10,
luaH_get = 24,
luaH_present = 48,
}
or this,
obj = {
{ N = 'Green1' },
{ N = 'Green' },
{ N = 'Sky blue99' }
}
I can code in a few languages but I'm very new to Lua, and tables are really confusing to me. I can't seem to work out how to adapt the code in the examples to be able to sort a simple table.
This is my table:
local players = {"barry", "susan", "john", "wendy", "kevin"}
I want to sort these names alphabetically. I understand that Lua tables don't preserve order, and that's what's confusing me. All I essentially care about doing is just printing these names in alphabetical order, but I feel I need to learn this properly and know how to index them in the right order to a new table.
The examples I see are like this:
local function cmp(a, b)
a = tostring(a.N)
b = tostring(b.N)
local patt = '^(.-)%s*(%d+)$'
local _,_, col1, num1 = a:find(patt)
local _,_, col2, num2 = b:find(patt)
if (col1 and col2) and col1 == col2 then
return tonumber(num1) < tonumber(num2)
end
return a < b
end
table.sort(obj, cmp)
for i,v in ipairs(obj) do
print(i, v.N)
end
or this:
function pairsByKeys (t, f)
local a = {}
for n in pairs(t) do table.insert(a, n) end
table.sort(a, f)
local i = 0 -- iterator variable
local iter = function () -- iterator function
i = i + 1
if a[i] == nil then return nil
else return a[i], t[a[i]]
end
end
return iter
end
for name, line in pairsByKeys(lines) do
print(name, line)
end
and I'm just absolutely thrown by this as to how to do the same thing for a simple 1D table.
Can anyone please help me to understand this? I know if I can understand the most basic example, I'll be able to teach myself these harder examples.
local players = {"barry", "susan", "john", "wendy", "kevin"}
-- sort ascending, which is the default
table.sort(players)
print(table.concat(players, ", "))
-- sort descending
table.sort(players, function(a,b) return a > b end)
print(table.concat(players, ", "))
Here's why:
Your table players is a sequence.
local players = {"barry", "susan", "john", "wendy", "kevin"}
Is equivalent to
local players = {
[1] = "barry",
[2] = "susan",
[3] = "john",
[4] = "wendy",
[5] = "kevin",
}
If you do not provide keys in the table constructor, Lua will use integer keys automatically.
A table like that can be sorted by its values. Lua will simply rearrange the index value pairs in respect to the return value of the compare function. By default this is
function (a,b) return a < b end
If you want any other order you need to provide a function that returs true if element a comes befor b
Read this https://www.lua.org/manual/5.4/manual.html#pdf-table.sort
table.sort
Sorts the list elements in a given order, in-place, from list[1] to
list[#list]
This example is not a "list" or sequence:
lines = {
luaH_set = 10,
luaH_get = 24,
luaH_present = 48,
}
Which is equivalent to
lines = {
["luaH_set"] = 10,
["luaH_get"] = 24,
["luaH_present"] = 48,
}
it only has strings as keys. It has no order. You need a helper sequence to map some order to that table's element.
The second example
obj = {
{ N = 'Green1' },
{ N = 'Green' },
{ N = 'Sky blue99' }
}
which is equivalent to
obj = {
[1] = { N = 'Green1' },
[2] = { N = 'Green' },
[3] = { N = 'Sky blue99' },
}
Is a list. So you could sort it. But sorting it by table values wouldn't make too much sense. So you need to provide a function that gives you a reasonable way to order it.
Read this so you understand what a "sequence" or "list" is in this regard. Those names are used for other things as well. Don't let it confuse you.
https://www.lua.org/manual/5.4/manual.html#3.4.7
It is basically a table that has consecutive integer keys starting at 1.
Understanding this difference is one of the most important concepts while learning Lua. The length operator, ipairs and many functions of the table library only work with sequences.
This is my table:
local players = {"barry", "susan", "john", "wendy", "kevin"}
I want to sort these names alphabetically.
All you need is table.sort(players)
I understand that LUA tables don't preserve order.
Order of fields in a Lua table (a dictionary with arbitrary keys) is not preserved.
But your Lua table is an array, it is self-ordered by its integer keys 1, 2, 3,....
To clear up the confusing in regards to "not preserving order": What's not preserving order are the keys of the values in the table, in particular for string keys, i.e. when you use the table as dictionary and not as array. If you write myTable = {orange="hello", apple="world"} then the fact that you defined key orange to the left of key apple isn't stored. If you enumerate keys/values using for k, v in pairs(myTable) do print(k, v) end then you'd actually get apple world before orange hello because "apple" < "orange".
You don't have this problem with numeric keys though (which is what the keys by default will be if you don't specify them - myTable = {"hello", "world", foo="bar"} is the same as myTable = {[1]="hello", [2]="world", foo="bar"}, i.e. it will assign myTable[1] = "hello", myTable[2] = "world" and myTable.foo = "bar" (same as myTable["foo"]). (Here, even if you would get the numeric keys in a random order - which you don't, it wouldn't matter since you could still loop through them by incrementing.)
You can use table.sort which, if no order function is given, will sort the values using < so in case of numbers the result is ascending numbers and in case of strings it will sort by ASCII code:
local players = {"barry", "susan", "john", "wendy", "kevin"}
table.sort(players)
-- players is now {"barry", "john", "kevin", "susan", "wendy"}
This will however fall apart if you have mixed lowercase and uppercase entries because uppercase will go before lowercase due to having lower ASCII codes, and of course it also won't work properly with non-ASCII characters like umlauts (they will go last) - it's not a lexicographic sort.
You can however supply your own ordering function which receives arguments (a, b) and needs to return true if a should come before b. Here an example that fixes the lower-/uppercase issues for example, by converting to uppercase before comparing:
table.sort(players, function (a, b)
return string.upper(a) < string.upper(b)
end)

How to find the key in hash by a key within its nested hash

There is a nested hash, I need to find the first level key by the key inside of it. For instance,
hash = {
a: {
first: 0,
second: 1
},
b: {
third: 2
}
}
I am given :first and I need to find the key it belongs to, in this case it would be :a . Thanks in advance
If you wish to interrogate the hash multiple times, for different inner keys (:first, :second, and so on) you may wish to construct the following hash before the interrogations begin.
hash = { a: { first: 0, second: 1 }, b: { third: 2 } }
h = hash.each_with_object({}) { |(k,v),h| v.each { |kk,_| h[kk] = k } }
#=> {:first=>:a, :second=>:a, :third=>:b}
so that later you may simply do hash lookups:
h[:first]
#=> :a
If the hash could look like this:
hash = { a: { first: 0, second: 1 }, b: { third: 2, first: 3 } }
you may wish to define h as follows:
h = hash.each_with_object({}) do |(k,v),h|
v.each { |kk,_| h.update(kk=>[k]) { |_,o,n| o+n } }
end
#=> {:first=>[:a, :b], :second=>[:a], :third=>[:b]}
This uses the form of Hash#update (a.k.a. merge!) that employs a block (here { |_,o,n| o+n }) to determine the values of keys that are present in both hashes being merged. See the doc for explanations of the three block variables _, o and n. I used _ for the variable holding the common key to tell the reader that it is not used in the block calculations. That is common practice, though you might see, for example, _key in place of _.
You can use Enumerable#find and Hash#key?:
Hash[*hash.find { |_, value| value.key?(:first) }]
# {:a=>{:first=>0, :second=>1}}
Really, being a Hash it's possible you can have the same key in different hashes within the "main" hash, so probably select is an option as well.
You can extract the keys and then find the one for which hash has a key named :first:
hash.keys.find { |k| hash[k].key?(:first) }
#=> :a
Use select instead of find to get an array of all matching keys (if there can be multiple).

Select from Tarantool by secondary index with sort by another field and limit/offset

I have some space top with fields:
-id,
-status,
-rating
I have two indexes for space top:
--primary
box.space.top:create_index('primary', { type = 'TREE', unique = true, parts = { 1, 'NUM' } })
--status
box.space.top:create_index('status', { type = 'TREE', unique = false, parts = { 2, 'NUM' } })
I can select by id or status
--select by id
space.top.index.primary:select(someId)
--select by status with limit/offset
space.top.index.status:select({someStatus}, {iterator = box.index.EQ, offset = 0, limit = 20})
Sometimes i need select by status with ordering by rating.
What is the best way? Create another index with parts status, rating and make some tricky query if it`s possible? Or continue select by status and make sort by rating in Lua procedure?
Thanks!
UPD:
Thanks, Kostya!
I modified index status like this:
box.space.top:create_index('status_rating', { type = 'TREE', unique = false, parts = { 2, 'NUM', 3 'NUM' } })
And now i can query:
local active_status = 1
local limit = 20
local offset = 0
box.space.top.index.status_rating:select({active_status}, {iterator = box.index.LE, offset=offset, limit=limit})
Great!
Doesn't make sense to create the third index, if you need to order by rating, just include it into the second index as the second part, and use GE/GT iterator, the data will come out ordered. This is an in-memory database, adding more parts to an index doesn't use up more memory, only slows down insertion a bit.
Call with GE/LE iterator and partial index may work not as expected than there is no matching tuples or limit is too high.
Suppose, we have following tuples (status, rating):
{ 1, 1 }
{ 3, 1 }
{ 3, 2 }
Than call
box.space.top.index.status_rating:select({2}, {iterator = box.index.GE, limit=1})
will return tuple {3, 1} as it greater than {2}
And call
box.space.top.index.status_rating:select({1}, {iterator = box.index.GE, limit=2})
will return two tuples {1, 1}, {3, 1}
In both case tuple {3, 1} may be not expected

how to sort groovy list values based on some criteria

I have one scenario to sort the values based domain class property. This property may acept all numeric and alphanumeric values in the format XXX-1.
def res= Book.listOrderByName()
or
def res = Book.findAll("from Book order by name")
Giving the same result and result is displaying first numbers latter alphanumeric values.
My problem is :
these values are sorted before -.
for example i have AB-1,AB-2,...AB-12.
The result is displayed as AB-1,AB-10.AB-11,AB-2,AB-3,..AB-9
I have result like:
[18001,18002,2,300,3901,42,9,AB-1,AB-10,AB-2,AB-21,AB-9]
It should display the value as:
[2,9,42,300,3901,18001,18002,AB-1,AB-2,AB-9,AB-10,AB-21]
Run this in the Groovy console:
List sort(list) {
list.sort {a, b ->
a.class == b.class ? a <=> b : a instanceof Integer ? -1 : 1
}
}
// Test the sort function
def list = [18001,18002,2,300,3901,42,9,'AB-1','AB-10','AB-2','AB-21','AB-9']
assert sort(list) == [2, 9, 42, 300, 3901, 18001, 18002, 'AB-1', 'AB-10', 'AB-2', 'AB-21', 'AB-9']

How to quickly initialise an associative table in Lua?

In Lua, you can create a table the following way :
local t = { 1, 2, 3, 4, 5 }
However, I want to create an associative table, I have to do it the following way :
local t = {}
t['foo'] = 1
t['bar'] = 2
The following gives an error :
local t = { 'foo' = 1, 'bar' = 2 }
Is there a way to do it similarly to my first code snippet ?
The correct way to write this is either
local t = { foo = 1, bar = 2}
Or, if the keys in your table are not legal identifiers:
local t = { ["one key"] = 1, ["another key"] = 2}
i belive it works a bit better and understandable if you look at it like this
local tablename = {["key"]="value",
["key1"]="value",
...}
finding a result with : tablename.key=value
Tables as dictionaries
Tables can also be used to store information which is not indexed
numerically, or sequentially, as with arrays. These storage types are
sometimes called dictionaries, associative arrays, hashes, or mapping
types. We'll use the term dictionary where an element pair has a key
and a value. The key is used to set and retrieve a value associated
with it. Note that just like arrays we can use the table[key] = value
format to insert elements into the table. A key need not be a number,
it can be a string, or for that matter, nearly any other Lua object
(except for nil or 0/0). Let's construct a table with some key-value
pairs in it:
> t = { apple="green", orange="orange", banana="yellow" }
> for k,v in pairs(t) do print(k,v) end
apple green
orange orange
banana yellow
from : http://lua-users.org/wiki/TablesTutorial
To initialize associative array which has string keys matched by string values, you should use
local petFamilies = {["Bat"]="Cunning",["Bear"]="Tenacity"};
but not
local petFamilies = {["Bat"]=["Cunning"],["Bear"]=["Tenacity"]};

Resources