in Mongoid 3, can I build a Queryable and then pass it to a where method? - mongodb

The docs between Origin and Mongoid aren't really clear on how to use a Origin::Queryable object. Can I build a Origin::Queryable object up and then pass it to a ModelName.where method? It seems that I can't but on the other hand, seems like a completely sensible thing to do. I can picture a situation where I build a Queryable based on some logic, then pass that to the Model's where clause. Is this possible and I'm just not doing it right?
This is what I'm picturing:
class Criteria
include Origin::Queryable
end
criteria = Criteria.new
criteria.where(category: 'vacuum').ne(dept: 'home')
vacuums = Product.where(criteria)
That's how I'm thinking it would work, but it doesn't. What do I do with the Criteria object after I build it?

So it works like this:
c = Criteria.new
c = c.where(category: 'a').ne(dept: 'home')
Then you have your criteria c , now you just use it, if you are using the 10gen driver you can use like this:
collection.find(c.selector, c.options)
Or using Moped:
session[:collection].find(c.selector).select(c.options.fields)
this should work, just did some local tests and it was fine for me.

Related

Zend\db\sql - prepareStatementForSqlObject - still need to bind or worry about sql injection?

I'm using zf 2.4 and for this example in Zend\db\sql. Do I need to worry about sql injection or do I still need to do quote() or escape anything if I already use prepareStatementForSqlObject()? The below example will do the blind variable already?
https://framework.zend.com/manual/2.4/en/modules/zend.db.sql.html
use Zend\Db\Sql\Sql;
$sql = new Sql($adapter);
$select = $sql->select();
$select->from('foo');
$select->where(array('id' => $id));
$statement = $sql->prepareStatementForSqlObject($select);
$results = $statement->execute();
The Select class will cleverly check your predicate(s) and add them in a safe manner to the query to prevent SQL-injection. I'd recommend you to take a look at the source for yourself so I'll point you to the process and the classes that are responsible for this in the latest ZF version.
Predicate Processing
Take a look at the class PredicateSet. The method \Zend\Db\Sql\Predicate::addPredicates determines the best way to handle your predicate based on their type. In your case you are using an associative array. Every item in that array will be checked and processed based on type:
If an abstraction replacement character (questionmark) is found, it will be turned into an Expression.
If the value is NULL, an IS NULL check will be performed on the column found in the key: WHERE key IS NULL.
If the value is an array, and IN check will be performed on the kolumn found in the key: WHERE key IN (arrayVal1, arrayVal2, ...).
Otherwise, the predicate will be a new Operator of the type 'equals': WHERE key = value.
In each case the final predicate to be added to the Select will be implementing PredicateInterface
Preparing the statement
The method \Zend\Db\Sql\Sql::prepareStatementForSqlObject instructs its adapter (i.e. PDO) to create a statement that will be prepared. From here it gets a little bit more complicated.
\Zend\Db\Sql is where the real magic happens where in method \Zend\Db\Sql::createSqlFromSpecificationAndParameters the function vsprintf is used to build the query strings, as you can see here.
NotePlease consider using the new docs.framework.zend.com website from now on. This website is leading when it comes to documentation of the latest version.

Generating and consuming an array within a StringTemplate-4 template

I'm new to StringTemplate4 and probably I am going to ask something overly simple, impossible or stupid but I couldn't find any other information on it.
So far, I have set this minimal set of templates:
define(name,arity) ::= "<name>(<vars(arity)>)."
vars(n) ::= "<n:var();separator=\", \">"
var(n) ::= "V<n>"
and I would like to get:
pred(V1, V2, V3).
by calling the following code:
STGroup group = new STGroupFile(...);
ST st = group.getInstanceOf("define");
st.add("name", "pred");
st.add("arity", 3);
String result = st.render();
Is it possible? Many thanks in advance.
StringTemplate doesn't have built-in operators for repeating. Instead, you'll need to iterate, like described in the following question.
Is there anything like Enumerable.Range(x,y) in Java?
Keep in mind that you'll need to pass an Iterator<T> and not an Iterable<T> due to a current limitation in StringTemplate (the interpreter supports Collection<T>, but not Iterable<T>). If you want to use the built-in iteration variable i or i0, you could also pass an appropriately sized new Object[n].

how to test if a string DON'T match using protractor

I'm migrating my karma-ng-scenario tests suite to protractor. I would like to do something like
// karma-ng-scenario
expect(element('legend').text()).not().toBe("LOGIN_CONNECT");
in the protractor way. But it seems there isn't a not() function.
I'm using angular-translate to bind the LONGIN_CONNECT string into multiple languages and I want to test if the string is translated.
More globally, is there a a way test if something is different ? ... don't have a class, don't exists on the page, is not selected, ...
It is definitely worth looking at the API docs. I have these open pretty much all the time.
There are lots of Web Driver functions you can use like isEnabled(), isDisplayed(), isSelected() etc. Protractor uses Jasmine syntax so you can use '.toBe(false)' to assert things are false.
To check for classes, you can do something like:
expect(myElement.getAttribute('class')).toContain('my-class-name');
To compare strings and assert that they do NOT match you could use .not. Jasmine docs
say:
Every matcher's criteria can be inverted by prepending .not:
expect(x).not.toEqual(y); compares objects or primitives x and y and
passes if they are not equivalent
You can use something like:
expect(model.getText()).not.toContain('abcdef');
There is a .not property nowadays.
I'm using the following to check for NOT matching:
expect(element('legend').text() === "LOGIN_CONNECT").toBe(false);

Updating data in SORM seems possible (even though I was told it aimed at immutable data...)

I was told that SORM aims at immutable data. It's not written on the website - at least not in the main parts I was looking at, so I was a bit surprized of the rigidity of the claim. I was just aware it would recommend to do so. But maybe I was just missing something.
The examples tell you to use a ".copy(propery = newvalue)" before calling a Db.save() on the object. So thats a hint.
I was interrested in what would happen if I would just change the data and update it in the database. Strangely the following just worked fine:
case class Agent( var name : String )
object Db extends Instance(
entities = Set( Entity[Agent]() ),
url = "jdbc:h2:mem:hansi"
)
class SORMTest extends FunSuite {
test("Update") {
// Store values in the db:
val agent = Db.save( Agent("test") )
agent.name = "hansi"
Db.save(agent)
}
It produced an update statement in the database that changed the name property for the corresponding id.
Is it kind of crazy to do so? Any comments from the developers?
I was told that SORM aims at immutable data. It's not written on the website
It's stated plenty of times that SORM strongly follows functional programming idioms. This implies operation on immutable data-structures only.
The examples tell you to use a ".copy(propery = newvalue)" before calling a Db.save() on the object.
That's where you're wrong. The examples tell you to use .copy(..) to get an updated immutable value of the object it's called on, calling it before calling a Db.save() per se as in the following:
agent.copy(name = "new name")
Db.save(agent)
will have absolutely no effect, because, once again, .copy() doesn't mutate the object it's called on, instead it returns an updated copy of this object. So the proper use is the following:
val updatedAgent = agent.copy(name = "new name")
Db.save(updatedAgent)
or simply:
Db.save( agent.copy(name = "new name") )
But the fact is all the above has to do with SORM only as much as it has to do with functional programming in Scala in general. This is really a very basic stuff about how case classes are supposed to be used. So please do yourself a favor and introduce yourself to basics of functional programming. This will wipe out all the questions on SORM you've already had and, I'm sure, plenty of those which are comming up otherwise.
Your example works and it's supposed to, but it doesn't change the fact that it goes against the basic idioms of functional programming and as such is an unidiomatic use of SORM.

How to Correctly Build a MongoDB Nested property Name using C# Driver

I must be missing something blindingly obvious. Somebody please shame me;
I'm building 2.2 Aggregation queries, which aren't natively supported by the C# Linq Driver, so I'm having to build up stringified names for nested properties using dotted notation. Say I have a structure like this;
db.so.insert({
a:1,
b:2,
n : {
z:4,
x:5,
y: {
v:"value",
}
}
});
So to reference the "value" I would need to use the name n.y.v or n[y][v]. Now, since I'm receiving the choice of field property names for the query from the web client (http://www.demo.org/exampleQuery?field1=n&field2=y&field3=v) I need to construct the property names thus;
var fieldNameForQuery = field1+"."+field2+"."+field3;
I'm obviously nervous about this, so of course I'm defending against NOSQL Injection by sanitising my input parameters, but I'd much rather be using the C# driver for this instead.
I guess I'd like something like;
MongoDB.Driver.BuildNestedFieldName(field1, field2, field3));
which is basically what I've had to write myself, but it feels like a kludge, and I'd rather not maintain the responsibility for building DB safe field names this way.
There currently isn't a function to do what you are wanting. However, if all the function does is stick "."'s in the middle, then we aren't solving an injection problem because the stuff we are inserting can't have been injected... The injection problem would be solved by ensuring that "field1", "field2", and "field3" are valid values for field names. Of course, there isn't much that is invalid according to http://bsonspec.org/#/specification. The only thing we'd be checking for is that there aren't 2 null terminators in the string. So... that doesn't leave us with much we can do.
Does this make sense?