Dynamic wheres using TypeORM - typeorm

I need to generate a query that looks something like:
SELECT v.* FROM versions v
WHERE
(v.id1 = 1 AND v.id2 = 1) OR
(v.id1 = 3 AND v.id2 = 2) OR
(v.id1 = 5 AND v.id2 = 6) OR ...
The parameter to my function contains a list of these paired ids. Unfortunately, id1 and id2 are not the primary keys of this table so I can't use .whereIdsIn().
I am aware of the Brackets object but can't for the life of me figure out how to create a dynamic number of them.

Since you put a generic query, I'll try to answer this generally. You can do something like this:
async foo(tupleList: [number, number][]) {
const builder = createQueryBuilder(Version, 'v');
for (const tuple of tupleList) {
builder.orWhere(new Brackets(qb => {
qb.where("v.id1 = :id1", { id1: tuple[0] })
.andWhere("v.id2 = :id2", { id2: tuple[1] })
}));
}
const result = await builder.getMany();
}

Related

breeze query where clause is not executed

I'm quite new to using breeze and at the moment stuck with something which seems very simple.
I have a API call which returns 4 locations. Then using breeze, I'm trying to filter it down using a where clause as follows:
function getLocations(clientId) {
var self = this;
return EntityQuery.from('GetLocations')
.withParameters({ clientId: clientId })
.where("activeStatus", "==", "0")
.expand('LocationType')
.using(self.manager)
.execute()
.then(querySucceeded, this._queryFailed);
function querySucceeded(data) {
if (data.results.length > 1) {
locations = data.results;
}
return locations;
}
}
Ideally, this should give me 0 rows, because in all 4 rows the 'activeStatus' is 1. However, it still shows me all 4 results. I tried with another filter for locationType, and it's the same result. The breeze side where clause does not get executed.
Update to answer the questions:
Following is how the API call in my controller looks like:
public object GetLocations(int clientId) {
}
As you see it only accepts the clientId as a parameter hence I use the with parameter clause. I was thinking that breeze will take care of the activeStatus where clause and I don't have to do the filter on that in the back-end. Is that wrong?
Can someone help with this?
The Breeze documentation indicates that the withParameters is usually used with non-.NET backends or servers which do not recognize oData URIs. Is it possible that the where clause is being ignored because of .withParameters? Can't you rewrite the where clause using the clientID filter?
function getLocations(clientId) {
var self = this;
var p1 = new breeze.Predicate("activeStatus","==","0");
var p2 = new breeze.Predicate("clientId","==",clientId);
var p = p1.and(p2)
return EntityQuery.from('GetLocations')
.where(p)
.expand('LocationType')
.using(self.manager)
.execute()
.then(querySucceeded, this._queryFailed);
function querySucceeded(data) {
if (data.results.length > 1) {
locations = data.results;
}
return locations;
}
}
I'd try this first. Or put the where clause in the withParameters statement, depending on your backend. If that doesn't work, then there might be other options.
Good Luck.
EDIT: An example that I use:
This is the API endpoint that I query against:
// GET: breeze/RST_ClientHistory/SeasonClients
[HttpGet]
[BreezeQueryable(MaxExpansionDepth = 10)]
public IQueryable<SeasonClient> SeasonClients()
{
return _contextProvider.Context.SeasonClients;
}
And here is an example of a query I use:
// qFilters is object. Values are arrays or strings, keys are id fields. SeasonClients might also be Clients
// Setup predicates
var p, p1;
// link up the predicates for passed data
for (var f in qFilters) {
var compareOp = Object.prototype.toString.call(qFilters[f]) === '[object Array]' ? 'in' : '==';
if (!qFilters[f] || (compareOp == 'in' && qFilters[f].length == 0)) continue;
fLC = f.toLowerCase();
if (fLC == "countryid") {
p1 = breeze.Predicate("District.Region.CountryId", compareOp, qFilters[f]);
} else if (fLC == "seasonid") {
p1 = breeze.Predicate("SeasonId", compareOp, qFilters[f]);
} else if (fLC == "districtid") {
p1 = breeze.Predicate("DistrictId", compareOp, qFilters[f]);
} else if (fLC == "siteid") {
p1 = breeze.Predicate("Group.Site.SiteId", compareOp, qFilters[f]);
} else if (fLC == "groupid") {
p1 = breeze.Predicate("GroupId", compareOp, qFilters[f]);
} else if (fLC == "clientid" || fLC == 'seasonclientid') {
p1 = breeze.Predicate("ClientId", compareOp, qFilters[f]);
}
// Setup predicates
if (p1) {
p = p ? p.and(p1) : p1;
}
}
// Requires [BreezeQueryable(MaxExpansionDepth = 10)] in controller
var qry = breeze.EntityQuery
.from("SeasonClients")
.expand("Client,Group.Site,Season,VSeasonClientCredit,District.Region.Country,Repayments.RepaymentType")
.orderBy("DistrictId,SeasonId,GroupId,ClientId");
// Add predicates to query, if any exist
if (p) qry = qry.where(p);
return qry;
That's longer than it needs to be, but I wanted to make sure a full working example is in here. You will notice that there is no reason to use .withParameters. As long as the Context is set up properly on the server, chaining predicates (where clauses) should work fine. In this case, we are creating where clauses with up to 10 ANDs filtering with strict equality or IN a collection, depending on what is passed in the qFilters Object.
I think you should probably get rid of the parameter in your backend controller, make the method parameterless, and include the clientId match as an additional predicate in your query.
This approach also makes your API endpoint much more flexible -- you can use it for a wide variety of queries, even if the ClientId has nothing to do with them.
Does this help? Let me know if you have any more questions?

Retrieve table name

Is there a way to retrieve the name of a table? For example, from this table I want extract only the keys name "Mimic", "Molibdeno", "Tamarindo", "Wrenna"
UnitScanDB = {
profiles = {
Mimic = {
...
},
Molibdeno = {
...
},
Tamanrindo = {
...
},
Wrenna = {
...
}
}
}
You can iterate over the inner table using pairs:
for k in pairs(UnitScanDB.profiles) do
-- handle k
end
Using the above loop, you could, for example, copy all of the keys into a new table:
local names = {}
for k in pairs(UnitScanDB.profiles) do
table.insert(names, k)
end
You can simply access those keys by their name, like so:
mimic = UnitScanDB.profiles.Mimic
molibdeno = UnitScanDB.profiles.Molibdeno

zf2 select columns from joined tables - how?

I feel like I must me missing something very simple. It's a very simple task, all I want to do is get something like:
SELECT * FROM lookup_items
JOIN lookup ON lookup_items.lookup_id = lookup.id
This returns all the columns for all the joined tables, in regular SQL. Here's my attempt in zf2:
$select = new Select();
$select->from('lookup_items');
$select->join('lookup', 'lookup_items.lookup_id = lookup.id');
The result set only includes the columns in 'lookup_items'. I've tried various ways to get the 'lookup' columns, including:
$select->columns(array('lookup_items.*', 'lookup.*'));
But they all just blow up. Surely there's a way to do this, and it's just so simple I'm missing it completely.
I thought a simple example would be avoid confusion, but here's more code:
class LookupItemsTable extends AbstractTableGateway
{
public function getList($resource)
{
$system_name = str_replace('*', '%', strtoupper($resource));
$joinTable = 'lookup';
$select = new Select();
$select->from($this->table);
$select->join($joinTable, "{$this->table}.lookup_id = {$joinTable}.id");
$where = array();
$where[] = "{$this->table}.enabled is true";
$where[] = "{$joinTable}.enabled is true";
$where[] = "UPPER({$joinTable}.system_name) ilike '{$system_name}'";
$select->where($where);
$sort[] = 'sort_order ASC';
$sort[] = 'value ASC';
$select->order($sort);
$rowset = $this->selectWith($select);
return $rowset;
}
}
Where:
$resource = $this->params()->fromRoute('resource', 'BUSINESS');
And $this->table is 'lookup_items'. Really all I want to do is get columns from both joined tables. I guess there's a zf2 way to just make a straight SQL statement without all the OO falderal, so I could just force it that way. But I'd rather work within the framework as much as possible.
Just change this line
$select->join('lookup', 'lookup_items.lookup_id = lookup.id');
to
$select->join('lookup', 'lookup_items.lookup_id = lookup.id', array('lookupcol1', 'lookupcol2');
Raj answer is the best one but it only works if you don't forget to add these fiels in your LookupItems model.
class LookupItems
{
// Your lookup_items fields here...
...
// And the added lookup fields here, the ones you add in the array
public $lookupcol1;
public $lookupcol2;
And in the exchangeArray method :
public function exchangeArray($data)
{
// .... your fields, and the new ones
$this->lookupcol1 = (! empty($data['lookupcol1'])) ? $data['lookupcol1'] : null;
$this->lookupcol2 = (! empty($data['lookupcol2'])) ? $data['lookupcol2'] : null;
}
I figured it out.
Added this:
$select->columns(array('*'));
And then this near the end:
$sql = new Sql($this->adapter);
$statement = $sql->prepareStatementForSqlObject($select);
$rowset = $statement->execute();
This returns the expected result, with the caveat that now my rows are returned as associative arrays instead of objects.
This is how you can create queries with join in zf2.
$resultSet = $this->select(function (Select $select) {
// omit the table name
//$select->from('foo');
$select->join('users', "users.id foo.createdby", 'firstname', '');
$select->order('id ASC');
// echo $select->getSqlString();// to print your query
});
$entities = array();
foreach ($resultSet as $row) {
$entity = new Entity\Foo();
$entity->setId($row->id)
->setFullname($row->fullname)
->setCaseid($row->caseid)
->setTestimonial($row->testimonial)
->setSortorder($row->sortorder)
->setActive($row->active)
->setCreated($row->created)
->setModified($row->modified)
->setFirstname($row->firstname)
->setCreatedby($row->createdby);
$entities[] = $entity;
}
return $entities;

LINQ - UNION - remove duplicated based on a single column

I have this linq query where i want to remove all the duplicates based on the column MAILADR (but keep the other columns):
Dim dataObject = (From a In db.TABLE1 Select New With {
.ID = a.BENUTZERNR,
.MAILADR = a.EMAIL,
.BENUTZERGRP = a.USRGRP
}) _
.Union(
(From b In db.TABLE12 Select New With {
.ID = b.ID,
.MAILADR = b.MAILADR,
.BENUTZERGRP = b.BENUTZERGRP
}) _
)
You can provide a comparison method (IEqualityComparer) on the overloaded Union method.
http://msdn.microsoft.com/en-us/library/bb358407.aspx
I ended up using the GroupByoperator:
dataObject = dataObject.GroupBy(Function(c) c.MAILADR).Select(Function(group) group.First())

LuaInterface: add a table to the script scope

Question: how can I insert a table from C# into 'LuaInterface' script scope using a C# object (preferably anonymous type)?
/// I want to do this, but it does not work
/// (complains that 'test' is userdata and not table
/// when I pass it to pairs() in the script)
//lua["test"] = new { A = 1, B = 2 };
/// another option
/// but building this string is a PITA (actual string is nested and long).
lua.DoString("test = { A = 1, B = 2 }");
// So I have to do this
lua.NewTable("test");
((LuaTable) lua["test"])["A"] = 1;
((LuaTable) lua["test"])["B"] = 2;
lua.DoString("for k,v in pairs(test) do print(k..': '..v) end");
You could fill a C# Dictionary with the keys and values you want to put inside the table. Then do what you're doing in the "I have to..." section, but inside a foreach loop.
Untested code:
var test = new Dictionary<string, int> {
{ "A", 1 },
{ "B", 2 }
};
foreach (var entry in test)
{
((LuaTable) lua]["test"])[entry.Key] = entry.Value;
}
I'd refactor this basic idea into a generic class for added flexibility.
I think if you want to serialize anonymous types into lua tables you will need to user reflection. Maybe you can try to write a lua table serializer. I think I would try to assemble my tables as string and pass it to Lua with DoString
I think the dictionary solution is good and you can use nested tables with without reflection. I tried Tuples, but they are not generic enough and eventually I fell back to the reflection idea.
I would create an extension method:
public static class LuaExt
{
public static LuaTable GetTable(this Lua lua, string tableName)
{
return lua[tableName] as LuaTable;
}
public static LuaTable CreateTable(this Lua lua, string tableName)
{
lua.NewTable(tableName);
return lua.GetTable(tableName);
}
public static LuaTable CreateTable(this Lua lua)
{
lua.NewTable("my");
return lua.GetTable("my");
}
}
Then I could write something like this:
var lua = new Lua();
var table = lua.CreateTable("test");
table["A"] = 1;
table["B"] = 1;
table["C"] = lua.CreateTable();
((LuaTable) table["C"])["A"] = 3;
table["D"] = lua.CreateTable();
((LuaTable)table["D"])["A"] = 3;
foreach (var v in table.Keys)
{
Console.WriteLine(v + ":" + table[v]);
}

Resources