AND condition in where clause - xero-api

I am trying to query the invoices with xero-ruby gem. I need to query with reference.
I build the query options as
opts = { statuses: %w[PAID DRAFT SUBMITTED AUTHORISED], where: { reference: ["Contains", job.quote_ref] } }
But on production it returns the following error:
Where clause invocation error: Operations on optional fields must be preceded by a null guard, e.g. \"[FieldName] != null AND [FieldName]...\""
I tried to add the null condition like this:
opts = { statuses: %w[PAID DRAFT SUBMITTED AUTHORISED], where: { reference: ["!=", nil] && ["Contains", job.quote_ref] } }
But since it is a hash, && condition doesn't work and it sends only the contains part.
I need help as Xero support does't help with ruby related issues
Tried building the query with multiple options:
opts = { statuses: %w[PAID DRAFT SUBMITTED AUTHORISED], where: { reference: ["!=", nil, "AND","contains", "1814"] }}
Not able to find a solution for this

Related

How do perform a graph query and join?

I apologize for the title, I don't exactly know how to word it. But essentially, this is a graph-type query but I know RavenDB's graph functionality will be going away so this probably needs to be solved with Javascript.
Here is the scenario:
I have a bunch of documents of different types, call them A, B, C, D. Each of these particular types of documents have some common properties. The one that I'm interested in right now is "Owner". The owner field is an ID which points to one of two other document types; it can be a Group or a User.
The Group document has a 'Members' field which contains an ID which either points to a User or another Group. Something like this
It's worth noting that the documents in play have custom IDs that begin with their entity type. For example Users and Groups begin with user: and group: respectively. Example IDs look like this: user:john#castleblack.com or group:the-nights-watch. This comes into play later.
What I want to be able to do is the following type of query:
"Given that I have either a group id or a user id, return all documents of type a, b, or c where the group/user id is equal to or is a descendant of the document's owner."
In other words, I need to be able to return all documents that are owned by a particular user or group either explicitly or implicitly through a hierarchy.
I've considered solving this a couple different ways with no luck. Here are the two approaches I've tried:
Using a function within a query
With Dejan's help in an email thread, I was able to devise a function that would walk it's way down the ownership graph. What this attempted to do was build a flat array of IDs which represented explicit and implicit owners (i.e. root + descendants):
declare function hierarchy(doc, owners){
owners = owners || [];
while(doc != null) {
let ownerId = id(doc)
if(ownerId.startsWith('user:')) {
owners.push(ownerId);
} else if(ownerId.startsWith('group:')) {
owners.push(ownerId);
doc.Members.forEach(m => {
let owner = load(m, 'Users') || load(m, 'Groups');
owners = hierarchy(owner, owners);
});
}
}
return owners;
}
I had two issues with this. 1. I don't actually know how to use this in a query lol. I tried to use it as part of the where clause but apparently that's not allowed:
from #all_docs as d
where hierarchy(d) = 'group:my-group-d'
// error: method hierarchy not allowed
Or if I tried anything in the select statement, I got an error that I have exceeded the number of allowed statements.
As a custom index
I tried the same idea through a custom index. Essentially, I tried to create an index that would produce an array of IDs using roughly the same function above, so that I could just query where my id was in that array
map('#all_docs', function(doc) {
function hierarchy(n, graph) {
while(n != null) {
let ownerId = id(n);
if(ownerId.startsWith('user:')) {
graph.push(ownerId);
return graph;
} else if(ownerId.startsWith('group:')){
graph.push(ownerId);
n.Members.forEach(g => {
let owner = load(g, 'Groups') || load(g, 'Users');
hierarchy(owner, graph);
});
return graph;
}
}
}
function distinct(value, index, self){ return self.indexOf(value) === index; }
let ownerGraph = []
if(doc.Owner) {
let owner = load(doc.Owner, 'Groups') || load(doc.Owner, 'Users');
ownerGraph = hierarchy(owner, ownerGraph).filter(distinct);
}
return { Owners: ownerGraph };
})
// error: recursion is not allowed by the javascript host
The problem with this is that I'm getting an error that recursion is not allowed.
So I'm stumped now. Am I going about this wrong? I feel like this could be a subquery of sorts or a filter by function, but I'm not sure how to do that either. Am I going to have to do this in two separate queries (i.e. two round-trips), one to get the IDs and the other to get the docs?
Update 1
I've revised my attempt at the index to the following and I'm not getting the recursion error anymore, but assuming my queries are correct, it's not returning anything
// Entity/ByOwnerGraph
map('#all_docs', function(doc) {
function walkGraph(ownerId) {
let owners = []
let idsToProcess = [ownerId]
while(idsToProcess.length > 0) {
let current = idsToProcess.shift();
if(current.startsWith('user:')){
owners.push(current);
} else if(current.startsWith('group:')) {
owners.push(current);
let group = load(current, 'Groups')
if(!group) { continue; }
idsToProcess.concat(group.Members)
}
}
return owners;
}
let owners = [];
if(doc.Owner) {
owners.concat(walkGraph(doc.Owner))
}
return { Owners: owners };
})
// query (no results)
from index Entity/ByOwnerGraph as x
where x.Owners = "group:my-group-id"
// alternate query (no results)
from index Entity/ByOwnerGraph as x
where x.Owners ALL IN ("group:my-group-id")
I still can't use this approach in a query either as I get the same error that there are too many statements.

Do strings need to be escaped inside parametrized queries?

I'm discovering Express by creating a simple CRUD without ORM.
Issue is, I'm not able to find any record through the Model.findBy() function
model User {
static async findBy(payload) {
try {
let attr = Object.keys(payload)[0]
let value = Object.values(payload)[0]
let user = await pool.query(
`SELECT * from users WHERE $1::text = $2::text LIMIT 1;`,
[attr, value]
);
return user.rows; // empty :-(
} catch (err) {
throw err
}
}
}
User.findBy({ email: 'foo#bar.baz' }).then(console.log);
User.findBy({ name: 'Foo' }).then(console.log);
I've no issue using psql if I surround $2::text by single quote ' like:
SELECT * FROM users WHERE email = 'foo#bar.baz' LIMIT 1;
Though that's not possible inside parametrized queries. I've tried stuff like '($2::text)' (and escaped variations), but that looks far from what the documentation recommends.
I must be missing something. Is the emptiness of user.rows related to the way I fetch attr & value ? Or maybe, is some kind of escape required when passing string parameters ?
"Answer":
As stated in the comment section, issue isn't related to string escape, but to dynamic column names.
Column names are not identifiers, and therefore cannot be dynamically set using a query parameter.
See: https://stackoverflow.com/a/50813577/11509906

prisma Order by relation has only _count property. Can not order by relation fields

consider following Prisma schema:
model Conversation {
id Int #id #default(autoincrement())
createdAt DateTime #db.Timestamp(6)
messages ConversationMessage[]
}
model ConversationMessage {
id Int #id #default(autoincrement())
text String #db.VarChar(1000)
sentAt DateTime #map("sent_at") #db.Timestamp(6)
conversationId Int? #map("conversation_id")
userId Int? #map("user_id")
conversation Conversation? #relation(fields: [conversationId], references: [id])
sender User? #relation(fields: [userId], references: [id])
}
I want to run such query so that I get a list of conversations ordered by date of their messages, i.e. the ones with new messages first.
prisma.conversation.findMany({
orderBy: {
messages: {
sentAt: 'desc'
}
},
...
})
But the only way that I can query now is like this, i.e. relation has only _count property somehow.
prisma.conversation.findMany({
orderBy: {
messages: {
'_count': 'desc'
}
},
...
})
Environment & setup
OS: Mac OS,
Database: PostgreSQL
Node.js version: v12.19.0
Prisma Version
prisma : 2.24.1
#prisma/client : 2.24.1
Current platform : darwin
Query Engine : query-engine 18095475d5ee64536e2f93995e48ad800737a9e4 (at node_modules/#prisma/engines/query-engine-darwin)
Migration Engine : migration-engine-cli 18095475d5ee64536e2f93995e48ad800737a9e4 (at node_modules/#prisma/engines/migration-engine-darwin)
Introspection Engine : introspection-core 18095475d5ee64536e2f93995e48ad800737a9e4 (at node_modules/#prisma/engines/introspection-engine-darwin)
Format Binary : prisma-fmt 18095475d5ee64536e2f93995e48ad800737a9e4 (at node_modules/#prisma/engines/prisma-fmt-darwin)
Default Engines Hash : 18095475d5ee64536e2f93995e48ad800737a9e4
Studio : 0.397.0
Preview Features : orderByRelation
Thank You!
While Prisma V2.19 introduced sort by relation aggregate value, as of this writing, the only aggregate property supported is count. To the best of my knowledge, what you are asking for is not directly supported by Prisma at the moment. It would be possible if they add min and max aggregate properties for sorting.
A possible workaround is to sort the messages inside Node.js after retrieval. I'm adding a solution that uses the orderByRelation preview feature to simplify the sorting and ensure the messages in a conversation are always ordered (newest first).
Updating Prisma Client to use orderByRelation preview feature.
First, update schema.prisma to add the preview feature
generator client {
provider = "prisma-client-js"
previewFeatures = ["orderByRelation"]
}
Now update the prisma client
prisma generate client
Get conversations and sort them by most recent message
// Assuming inside an async function
let unsortedConversations = await prisma.conversation.findMany({
include: {
messages: {
orderBy: {
sentAt: 'desc' // messages for each converastion will be ordered newest first.
}
}
},
// other conditions
})
unsortedConversations contains all required conversations, but they are unordered. You can sort it in the desired order by creating a custom comparator function.
function conversationComparatorFunction(conversationA, conversationB) {
// Conversations with 0 messages will be placed last in arbitrary order.
if (!conversationB.messages.length) return 1;
if (!conversationA.messages.length) return -1;
// sort conversations based on sentAt date of the first message.
// since messages were previously sorted, messages[0] always contain the most recent message.
if (conversationA.messages[0].sentAt > conversationB.messages[0].sentAt) {
return -1;
} else if (conversationA.messages[0].sentAt < conversationB.messages[0].sentAt) {
return 1;
} else return 0;
}
let sortedConversations = unsortedConversations.sort(conversationComparatorFunction)
Be warned though, if the number of Conversation records is very large sorting on the application side could lead to poor performance, especially considering Node.js is single-threaded.
OrderBy relation is still a preview feature - you need to make sure to use the feature flag
generator client {
provider = "prisma-client-js"
previewFeatures = ["orderByRelation"]
}
https://www.prisma.io/docs/concepts/components/prisma-client/filtering-and-sorting#sort-by-relation-preview

Creating level codes with action script 2.0

I want to create level codes, like in sea of fire (http://armorgames.com/play/351/sea-of-fire)
I have a text input box with the instance name "code" and a button that has this code:
on (release) {
if (code = 96925) {
gotoAndStop(4);
}
if (code = 34468) {
gotoAndStop(5);
}
if (code = 57575) {
gotoAndStop(6);
}
if (code = 86242) {
gotoAndStop(7);
}
if (code = 99457) {
gotoAndStop(8);
}
if (code = 66988) {
gotoAndStop(10);
}
if (code = !96925 && !34468 && !57575 && !86242 && !99457 && !66988) {
gotoAndStop(3);
}
}
I've tried to use code.text instead of just code, I've also tried quotes around the numbers, also I tried both together but it always sends you to frame 10 even if the code is invalid.
You need to use conditional operator (==), not equality operator (=) in 'if' condition
Also if 'code' is a text field then you need to use code.text
You can put trace to check for the value of code.
I do not understand your last if condition
Instead you can use if - else if - else here.

PDO login script won't work

I changed this login script to PDO. Now it passes the username but get's stuck fetchAll line. I need help please. thanks
<?php
session_start();
include_once"includes/config.php";
if (isset($_POST['admin_login'])) {
$admin_user = trim($_POST['admin_user']);
$admin_pw = trim($_POST['admin_pw']);
if ($admin_user == NULL OR $admin_pw == NULL) {
$final_report.="Please complete all the fields below..";
} else {
$check_user_data = $db->prepare("SELECT * FROM `admin`
WHERE `admin_user`='$admin_user'");
$check_user_data->execute();
if ($check_user_data->fetchColumn() == 0) {
$final_report.="This admin username does not exist..";
} else {
$get_user_data = $check_user_data->fetchAll($check_user_data);
if ($get_user_data['admin_pw'] == $admin_pw) {
$start_idsess = $_SESSION['admin_user'] = "".$get_user_data['admin_user']."";
$start_passsess = $_SESSION['admin_pw'] = "".$get_user_data['admin_pw']."";
$final_report.="You are about to be logged in, please wait a few moments...";
header('Location: admin.php');
}
}
}
}
?>
Not checking return value prepare() or execute() for false. You need to check for SQL errors and handle them, stopping the code instead of continuing on blithely.
Not using query parameters in the prepared statement, still interpolating $_POST content into the query unsafely. You're missing the benefit of switching to PDO, and leaving yourself vulnerable to SQL injection attack.
You're storing passwords in plaintext, which is unsafe. See You're Probably Storing Passwords Incorrectly.
Do you really need to SELECT * if you only use the admin_pw column? Hint: no.
PDOStatement::fetchAll() returns an array of arrays, not just one array for a row. Read the examples in the documentation for fetchAll().