Multiple nesting in Falcor query - falcor

I am trying to query a multiple nested object with Falcor. I have an user which has beside other the value follower which itself has properties like name.
I want to query the name of the user and the first 10 follower.
My Falcor server side can be seen on GitHub there is my router and resolver.
I query the user with user["KordonDev"]["name", "stars"]. And the follower with user["KordonDev"].follower[0.10]["name", "stars"].
The route for follower is user[{keys:logins}].follower[{integers:indexes}] but this doesn't catch the following query.
I tried to add it as string query.
user["KordonDev"]["name", "stars", "follower[0..10].name"] doesn't work.
The second try was to query with arrays of keys. ["user", "KordonDev", "follower", {"from":0, "to":10}, "name"] but here I don't know how to query the name of the user.

As far as I know and looking on the path parser. There is no way to do nested queries.
What you want to do is batch the query and do two queries.
user["KordonDev"]["name", "stars"]
user["KordonDev"]["follower"][0..10].name
It seems that falcor does not support this, there is even a somewhat old issue discussing how people trying to do nested queries.
to the point about the current syntax leading people to try this:
['lolomo', 0, 0, ['summary', ['item', 'summary']]]
I can see folks trying to do the same thing with the new syntax:
"lolomo[0][0]['summary', 'item.summary']"
As soon as they know they can do:
"lolomo[0][0]['summary', 'evidence']"
So it seems deep nested queries is not a functionality.

Related

Why is TypeORM returning no records in this simple query?

I'm trying to get all the users on my system that match a complex where conditional with TypeORM. My end query would look something like this:
connection.createQueryBuilder()
.select().from(User, "user")
.where("email IS NULL OR email NOT LIKE '%#example.com'")
.getMany()
If I run that query with getCount() it works and tells me how many I have, but getMany() return []
In fact, I simplified it to this:
console.log(
await connection.createQueryBuilder()
.select().from(User, "user")
.getManyAndCount())
I get this surprising result (with logging enabled):
query: SELECT * FROM "user" "user"
query: SELECT COUNT(DISTINCT("user"."id")) as "cnt" FROM "user" "user"
[ [], 14 ]
Any ideas why I would get no users when the count shows 14? I run the query manually and it obviously shows the users... what's going on here?
The code that Carlo offered in one of the answers:
await connection.getRepository(User).findAndCount()
works, but that won't let me have my where clause (as far as I know, I'm still new to TypeORM). I'm just sharing this to show that the User model seems to be working fine, except when I use it with the query builder to select a bunch of users (counting and deleting works).
Keep your code syntax as simple as possible since TypeORM docs (now) are't perfect.
Try using Find Options since I can't find any getManyAndCount() method for QueryBuilder:
const users = await connection
.getRepository(User)
.findAndCount();
EDIT:
Of course you can have (complex) where clause with find.
You can chain multiple where clauses (OR) with a really simple syntax. Check out all options here.
Example that map your "raw" query:
const users = await connection
.getRepository(User)
.findAndCount({
where: [
{
email: IsNull(),
},
{
email: Not(Like('%#example.com')),
},
],
});
Hope it helps :)
Let me divide that step-by-step approach
despite of getManyAndCount() use getRawEntities()
you will get the data for sure by using 1st point
now concentrate on the keys you are getting on data
use the same key on your select query and done
if you didn't get records using getRawEntities():
I. try to use select * i.e, select()
II. check the column name and correct that
Additionally, It can also depend on your entity structure. Carefully check that too.

parameter based joins not susceptible for sql injection

I want to do non-standard query with join based on the parameters.
For example I have 2 tables: a_examples and b_examples both with fields: field_x and field_y.
I want to join rows when both tables have the same values on field_x(or field_y).
Example query can looks like this:
AExample.joins('INNER JOIN b_examples ON b_examples.field_x = a_examples.field_x')
The problem occurs when I have field name based on parameter.
For example I have variable field_name and want to use it for query. I can do it like this:
AExample.joins("INNER JOIN b_examples ON b_examples.#{field_name} = a_examples.#{field_name}")
This query works, but is susceptible for sql injection.
For where clause we have special syntax with ? to avoid sql injection but there isnt any such thing for joins. How can I make this query safe?
Do not attempt this:
(explanation below)
You can use the ActiveRecord::Sanitization module and write something like the following, inside your ActiveRecord model:
AExample.joins("INNER JOIN b_examples ON b_examples.#{sanitize_sql(field_name)} = a_examples.#{sanitize_sql(field_name)}")
Or you can include the module somewhere else and use it there (e.g. your controller).
Do use this, instead: (included from another answer)
AExample.joins("INNER JOIN b_examples ON b_examples.#{ActiveRecord::Base.connection.quote_column_name(field_name)} = a_examples.#{ActiveRecord::Base.connection.quote_column_name(field_name)}")
It will raise an error if the column is not found, preventing malicious code from entering your query.
However I wouldn't do this in my app as it looks suspicious, other programers may not understand what is happening, it may be implemented wrong, solid testing should be included, it may have bugs and such. In your problem, you only need to construct two different queries, with that information I would write something like:
case dynamic_field
when 'field_x'
AExample.joins('INNER JOIN b_examples ON b_examples.field_x = a_examples.field_x')
when 'field_y'
AExample.joins('INNER JOIN b_examples ON b_examples.field_y = a_examples.field_y')
else
raise "Some suspicious parameter was sent!: #{dynamic_field}"
end
Or even write scopes on your model and avoid this code to be flying around.
With problems of this nature, as with encryption, try to find a workaround and avoid implementing your own solutions as much as possible.
EDIT:
The method sanitize_sql is intended to sanitize conditions for a WHERE clause (ActiveRecord::Sanitization):
Accepts an array or string of SQL conditions and sanitizes them into a valid SQL fragment for a WHERE clause.
It is not an option as you try to sanitize for an INNER JOIN, or an ON clause.
Note that the ActiveRecord::Sanitization module only has options for WHERE, SET, ORDER and LIKE clauses. I was unable to find a sanitization method for a column name, an INNER JOIN or an ON clause. Perhaps is a useful funcionality that should be added on Rails on further version.
Using sanitize_sql with a string passes it almost unfiltered, so if the field_name variable has some malicious code as:
"field_x = a_examples.field_x; DROP TABLE a_examples; --"
It will be included in your query, without any error being raised.
This solution is not safe, and is for reasons like these that we should avoid writing code of this nature. Perhaps you find something helpful with Arel or other gems, but I would strongly advice not to.
EDIT 2:
Added the working solution to escape a column name. It raises an error if malicious code is being entered, as the column with that name will not be found.
You can sanitize parameters using ActiveRecord::Base.connection.quote(string) or even .quote_column

How to add attribute/property to each record/object in an array? Rails

I'm not sure if this is just a lacking of the Rails language, or if I am searching all the wrong things here on Stack Overflow, but I cannot find out how to add an attribute to each record in an array.
Here is an example of what I'm trying to do:
#news_stories.each do |individual_news_story|
#user_for_record = User.where(:id => individual_news_story[:user_id]).pluck('name', 'profile_image_url');
individual_news_story.attributes(:author_name) = #user_for_record[0][0]
individual_news_story.attributes(:author_avatar) = #user_for_record[0][1]
end
Any ideas?
If the NewsStory model (or whatever its name is) has a belongs_to relationship to User, then you don't have to do any of this. You can access the attributes of the associated User directly:
#news_stories.each do |news_story|
news_story.user.name # gives you the name of the associated user
news_story.user.profile_image_url # same for the avatar
end
To avoid an N+1 query, you can preload the associated user record for every news story at once by using includes in the NewsStory query:
NewsStory.includes(:user)... # rest of the query
If you do this, you won't need the #user_for_record query — Rails will do the heavy lifting for you, and you could even see a performance improvement, thanks to not issuing a separate pluck query for every single news story in the collection.
If you need to have those extra attributes there regardless:
You can select them as extra attributes in your NewsStory query:
NewsStory.
includes(:user).
joins(:user).
select([
NewsStory.arel_table[Arel.star],
User.arel_table[:name].as("author_name"),
User.arel_table[:profile_image_url].as("author_avatar"),
]).
where(...) # rest of the query
It looks like you're trying to cache the name and avatar of the user on the NewsStory model, in which case, what you want is this:
#news_stories.each do |individual_news_story|
user_for_record = User.find(individual_news_story.user_id)
individual_news_story.author_name = user_for_record.name
individual_news_story.author_avatar = user_for_record.profile_image_url
end
A couple of notes.
I've used find instead of where. find returns a single record identified by it's primary key (id); where returns an array of records. There are definitely more efficient ways to do this -- eager-loading, for one -- but since you're just starting out, I think it's more important to learn the basics before you dig into the advanced stuff to make things more performant.
I've gotten rid of the pluck call, because here again, you're just learning and pluck is a performance optimization useful when you're working with large amounts of data, and if that's what you're doing then activerecord has a batch api you should look into.
I've changed #user_for_record to user_for_record. The # denote instance variables in ruby. Instance variables are shared and accessible from any instance method in an instance of a class. In this case, all you need is a local variable.

Parse hash for value from a table

I am writing a AWS-Federation proxy in Rails. This means I grab for some groups using net-ldap on our local ActiveDirectory and want to compare those to a list and look for matches. My NetLDAP-searchresult is this hash:
[#<Net::LDAP::Entry:0x000000048cfdd0 #myhash={:dn=>["CN=Username,OU=Support,OU=mycompany ,OU=Organisation,DC=mycompany,DC=com"], :memberof=>["CN=My AWS Groupname,CN=Receiver,CN=Users,DC=mycompany,DC=com"]}>]
Now I want to parse this hash and look for matches in a local "groups" table. It looks like that:
Name AWS-Role
My AWS-Groupname Some Group
AWS-Othergroup Some Other-Group
I have a group-model.
What is a best practices approach? I've never done something like this before. Would I use a Regex here? Do I loop the groups through all tables? What's the rails way to do this?
edited for more information
I'm going to assume a few things here, since I don't know where you get the LDAP search results from, but assuming your hash looks like this:
EDIT:
based on the additional information:
// Example
require 'net-ldap'
entry = Net::LDAP::Entry.new
entry.dn = ["CN=Username,OU=Support,OU=mycompany ,OU=Organisation,DC=mycompany,DC=com"]
entry[:memberof] =["CN=My AWS Groupname,CN=Receiver,CN=Users,DC=mycompany,DC=com"]
name = entry.memberof.first.split(',').first.gsub('CN=', '')
And assuming you have a model called Group that is mapped to this "groups" table, you can do something like this:
Group.where(name: name).any?
If you find any results, it means you have a match in the table.
But this completely depends on the table structure and hash. To properly answer your question, I'd need to see what Objects you have in Rails, and what the structure of your Hash looks like.
EDIT:
Updated my answer based on the received feedback. Use code at own risk.

Ruby on Rails build query in pieces

There was a very similar question before but i still struggle.
Is it possible to build a query up in stages?
Let's say I have a search form with many text and select fields that may be chained with and/or or which could be blank.
So the sql statement should consist of several parts that are connected individually for each search.
I tried to create strings for every option and put them to a symbol? (i mean #options) and put that in the where clause (e.g. Product.where(#options) ). That works somehow but i have got troubles with this part: 'params[:query]' when it's in quotes. Either my sql statement says 'select products from products where (name like params[:query]') or if i try #{params[:query]} it says: select products from products (where 'name' like ''.)
So how can i chain different parts of a query?
I looking forward to your answers!
Never, ever, ever embed raw strings in your SQL. This is extremely bad form. You should always use the escaping mechanism provided by Rails or something equivalent to avoid ending up in serious trouble. Inserting content from params is very dangerous and should never be done as it only takes this to nuke your app: { :query => '\"-- DROP TABLE users;' }
Generally you use the helper methods provided by ActiveRecord to build up your query in stages:
scope = Product
if (params[:query].present?)
scope = scope.where([ 'name LIKE ?', "%#{params[:query]}%" ])
end
if (params[:example].present?)
scope = scope.where(:example => true)
end
#products = scope.all
You can build it up in stages like this, modifying the scope in-place each time, and then execute the final call to retrieve it. Generally that's when you use your paginator to split up the results.
It's okay to put pretty much anything in your options because it should be escaped by the time it hits the SQL phase, much as anything on the HTML side is escaped for you as well.
Don't confuse instance variables like #options with a symbol like :query. The two are very different things. Instance variables have the benefit of propagating to your view automatically, so they are often used extensively in controllers. Views should avoid modifying them whenever possible as a matter of style.

Resources