Rails 5 scope like multiple partial strings - ruby-on-rails

Say I have a scope like this:
scope :by_templates, ->(t) { joins(:template).where('templates.label ~* ?', t) }
How can I retrieve multiple templates with t like so?
Document.first.by_templates(%w[email facebook])
This code returns this error.
PG::DatatypeMismatch: ERROR: argument of AND must be type boolean, not type record
LINE 1: ...template_id" WHERE "documents"."user_id" = $1 AND (templates...

PostgreSQL allows you to apply a boolean valued operator to an entire array of values using the op any(array_expr) construct:
9.23.3. ANY/SOME (array)
expression operator ANY (array expression)
expression operator SOME (array expression)
The right-hand side is a parenthesized expression, which must yield an array value. The left-hand expression is evaluated and compared to each element of the array using the given operator, which must yield a Boolean result. The result of ANY is “true” if any true result is obtained. The result is “false” if no true result is found (including the case where the array has zero elements).
PostgreSQL also supports the array constructor syntax for creating arrays:
array[value, value, ...]
Conveniently, ActiveRecord will expand a placeholder as a comma-delimited list when the value is an array.
Putting these together gives us:
scope :by_templates, ->(templates) { joins(:template).where('templates.label ~* any(array[?])', templates) }
As an aside, if you're using the case-insensitive regex operator (~*) as a case-insensitive comparison (i.e. no real regex pattern matching going on) then you might want to use upper instead:
# Yes, this class method is still a scope.
def self.by_templates(templates)
joins(:template).where('upper(templates.label) = any(array[?])', templates.map(&:upcase) }
end
Then you could add an index to templates on upper(label) to speed things up and avoid possible issues with stray regex metacharacters in the templates. I tend to use upper case for this sort of thing because of oddities lie 'ß'.upcase being 'SS' but 'SS'.downcase being 'ss'.

Related

Open policy agent satisfy condition for all array items

Trying to wrap my head around this issue for a while - I have a JSON input which contains an array, say something like this:
{
"array" : [
{"foo": "bar"},
{"foo": "buzz"},
{"misbehaving": "object"}
]
}
My goal is to verify that all of the objects in the array satisfy the condition of having a field named foo (actual use-case is to make sure that all resources in cloud deployment have tags). My issue is that standard rego expressions are evaluated as "at least" and not "all", which means that expressions like:
all_have_foo_field {
input.array.foo
}
Are always returning true, even though some objects do not satisfy this. I've looked at this, but evaluating a regex returns true or false while my policy checks if field exists, meaning if it does not I get a 'var_is_unsafe' error.
Any ideas?
There are two ways to say "all fields of elements in X must match these conditions" (FOR ALL).
TLDR:
all_have_foo_field {
# use negation and a helper rule
not any_missing_foo_field
}
any_missing_foo_field {
some i
input.array[i]
not input.array[i].foo
}
OR
all_have_foo_field {
# use a comprehension
having_foo := {i | input.array[i].foo}
count(having_foo) == count(input.array)
}
The approach depends on the us case. If you want to know what elements do not satisfy the conditions, the comprehension is nice because you can use set arithmetic, e.g., {i | input.array[i]} - {i | input.array[i].foo} produces the set of array indices that do not have the field "foo". You probably want to assign these expressions to local variables for readability. See this section in the docs for more detail: https://www.openpolicyagent.org/docs/latest/policy-language/#universal-quantification-for-all.
In this case (as opposed to the answer you linked to) we don't have to use regex or anything like that since references to missing/undefined fields results in undefined and undefined propagates outward to the expression, query, rule, etc. This is covered to some extent in the Introduction.
All we have to do then is just refer to the field in question. Note, technically not input.array[i].foo would be TRUE if the "foo" field value false however in many cases undefined and false can be treated as interchangeable (they're not quite the same--false is a valid JSON value whereas undefined represents the lack of a value.) If you need to only match undefined then you have to assign the result of the reference to a local variable. In the comprehension case we can write:
# the set will contain all values i where field "foo" exists regardless
{i | _ = input.array[i].foo}
In the negation case we need an additional helper rule since not _ = input.array[i].foo would be "unsafe". We can write:
exists(value, key) { value[key] = _ }`
And now not exists(input[i], "foo") is only TRUE when the field "foo" is missing.
Note, differentiating between undefined and false is often not worth it--I recommend only doing so when necessary.

Ada vector of enumerated type

I am trying to created a vector of an enumerated type in Ada, but the compiler seems to expect an equality function overload. How do I telll the compiler to just use the default equal function. Here's what I have:
package HoursWorkedVector is new Ada.Containers.Vectors(Natural,DAY_OF_WEEK);
--where Day of week is defined as an enumeration
When I try to compile, I get the message:
no visible subprogram matches the specification for "="
Do I need to create a comparison function to have a vector of an enumerated type? Thanks in advance.
The definition of Ada.Containers.Vectors starts like this:
generic
type Index_Type is range <>;
type Element_Type is private;
with function "=" (Left, Right : Element_Type)
return Boolean is <>;
package Ada.Containers.Vectors is
The meaning of <> in a generic formal function is defined by RM 12.6(10):
If a generic unit has a subprogram_default specified by a box, and the
corresponding actual parameter is omitted, then it is equivalent to an
explicit actual parameter that is a usage name identical to the
defining name of the formal.
So if, as you said in the comments, DAY_OF_WEEK is defined in another package, your instantiation is equivalent to
package HoursWorkedVector is new Ada.Containers.Vectors(Natural, Other_Package.DAY_OF_WEEK, "=");
which doesn't work because the "=" that compares DAY_OF_WEEK values is not visible.
You can include Other_Package."=" in the instantiation, as suggested in a comment. There are at least three ways to make "=" visible, so that your original instantiation would work:
use Other_Package; This will make "=" directly visible, but it will also make everything else defined in that package directly visible. This may not be what you want.
use type Other_Package.DAY_OF_WEEK; This makes all the operators of DAY_OF_WEEK directly visible, including "<", "<=", etc., as well as all the enumeration literals, and any other primitive subprograms of DAY_OF_WEEK that you may have declared in Other_Package. This is probably the favorite solution, unless for some reason it would be a problem to make the enumeration literals visible.
Use a renaming declaration to redefine "=":
function "=" (Left, Right : DAY_OF_WEEK) return Boolean
renames Other_Package."=";
This makes "=" directly visible.
The compiler automatically selects the predefined equality operator:
with
Ada.Containers.Vectors;
package Solution is
type Day_Of_Week is (Work_Day, Holiday);
package Hours_Worked_Vector is
new Ada.Containers.Vectors (Index_Type => Natural,
Element_Type => Day_Of_Week);
end Solution;

Erlang matchspecs with tuple comparison

I want to use erlang datetime values in the standard format {{Y,M,D},{H,Min,Sec}} in a MNESIA table for logging purposes and be able to select log entries by comparing with constant start and end time tuples.
It seems that the matchspec guard compiler somehow confuses tuple values with guard sub-expressions. Evaluating ets:match_spec_compile(MatchSpec) fails for
MatchSpec = [
{
{'_','$1','$2'}
,
[
{'==','$2',{1,2}}
]
,
['$_']
}
]
but succeeds when I compare $2 with any non-tuple value.
Is there a restriction that match guards cannot compare tuple values?
I believe the answer is to use double braces when using tuples (see Variables and Literals section of http://www.erlang.org/doc/apps/erts/match_spec.html#id69408). So to use a tuple in a matchspec expression, surround that tuple with braces, as in,
{'==','$2',{{1,2}}}
So, if I understand your example correctly, you would have
22> M=[{{'_','$1','$2'},[{'==','$2',{{1,2}}}],['$_']}].
[{{'_','$1','$2'},[{'==','$2',{{1,2}}}],['$_']}]
23> ets:match_spec_run([{1,1,{1,2}}],ets:match_spec_compile(M)).
[{1,1,{1,2}}]
24> ets:match_spec_run([{1,1,{2,2}}],ets:match_spec_compile(M)).
[]
EDIT: (sorry to edit your answer but this was the easiest way to get my comment in a readable form)
Yes, this is how it must be done. An easier way to get the match-spec is to use the (pseudo) function ets:fun2ms/1 which takes a literal fun as an argument and returns the match-spec. So
10> ets:fun2ms(fun ({A,B,C}=X) when C == {1,2} -> X end).
[{{'$1','$2','$3'},[{'==','$3',{{1,2}}}],['$_']}]
The shell recognises ets:fun2ms/1. For more information see ETS documentation. Mnesia uses the same match-specs as ETS.

Input to the python join method can't be a list of numbers?

This gives me an error:
a = [1,2,3]
'\t'.join(a)
Is this because of the list elements being integers?
Indeed. Python needs explicit type conversion since it's strongly-typed.
>>> a = [1,2,3]
>>> '\t'.join(map(str, a))
'1\t2\t3'
Function map applies function (passed as first argument) to iterable (passed as second argument).
In this case it converts (str) each element of a into a string and returns the resulting list, that is consequently passed to method join of object '\t'.
see http://docs.python.org/library/stdtypes.html#str.join
Return a string which is the concatenation of the strings in the iterable iterable. The separator between elements is the string providing this method.
So the target should be array of strings.

<< and >> symbols in Erlang

First of all, I'm an Erlang rookie here. I need to interface with a MySQL database and I found the erlang-mysql-driver. I'm trying that out, and am a little confused by some of the syntax.
I can get a row of data from the database with this (greatly oversimplified for brevity here):
Result = mysql:fetch(P1, ["SELECT column1, column2 FROM table1 WHERE column2='", Key, "'"]),
case Result of
{data, Data} ->
case mysql:get_result_rows(Data) of
[] -> not_found;
Res ->
%% Now 'Res' has the row
So now here is an example of what `Res' has:
[[<<"value from column1">>, <<"value from column2">>]]
I get that it's a list of records. In this case, the query returned 1 row of 2 columns.
My question is:
What do the << and >> symbols mean? And what is the best (Erlang-recommended) syntax for turning a list like this into a records which I have defined like:
-record(
my_record,
{
column1 = ""
,column2 = ""
}
).
Just a small note: the results are not bit string comprehensions per see, they are just bit strings. However you can use bit string comprehensions to produce a sequence of bit strings (which is described above with the generators and that), much like lists and lists comprehensions.
you can use erlang:binary_to_list/1 and erlang:list_to_binary/1 to convert between binary and strings (lists).
The reason the mysql driver returns bit strings is probably because they are much faster to manipulate.
In your specific example, you can do the conversion by matching on the returned column values, and then creating a new record like this:
case mysql:get_result_rows(Data) of
[] ->
not_found;
[[Col1, Col2]] ->
#my_record{column1 = Col1, column2 = Col2}
end
These are bit string comprehensions.
Bit string comprehensions are analogous to List Comprehensions. They are used to generate bit strings efficiently and succinctly.
Bit string comprehensions are written with the following syntax:
<< BitString || Qualifier1,...,QualifierN >>
BitString is a bit string expression, and each Qualifier is either a generator, a bit string generator or a filter.
• A generator is written as:
Pattern <- ListExpr.
ListExpr must be an expression which evaluates to a list of terms.
• A bit string generator is written as:
BitstringPattern <= BitStringExpr.
BitStringExpr must be an expression which evaluates to a bitstring.
• A filter is an expression which evaluates to true or false.
The variables in the generator patterns shadow variables in the function clause surrounding the bit string comprehensions.
A bit string comprehension returns a bit string, which is created by concatenating the results of evaluating BitString for each combination of bit string generator elements for which all filters are true.
Example:
1> << << (X*2) >> ||
<<X>> <= << 1,2,3 >> >>.
<<2,4,6>>

Resources