How can I query Hasura API over HTTP to invoke SQL "WHERE LIKE" behavior? - hasura

I'm trying to update the ra-data-hasura library to allow filtering based upon partial matches. I've discovered how to call the server over HTTP via the PostMan tool, but cannot find a way to get the "where" property to look for partial (as opposed to exact) matches (see image below). Is there a way to this (e.g. call for something like "WHERE description LIKE 'Milestone%'")?
Image showing PostMan call to Hasura

Either use GraphQL:
http://example.com/v1/graphql
{
lifeplan_planning_type(
limit: 10,
offset: 0,
where: {description: {_like: "Milestone%"}}
) {
id
description
}
}
or a regular SQL:
http://example.com/v1/query
{
"type": "run_sql",
"args": {
"sql": "SELECT * FROM lifeplan.planning_type WHERE description LIKE "Milestone%" LIMIT 10 OFFSET 0 ORDER BY id ASC"
}
}
More info in Hasura's documentation:
https://hasura.io/docs/1.0/graphql/manual/api-reference/schema-metadata-api/run-sql.html#run-sql

Related

How to manually set the Firestore document ID saving a new document calling Firestore API?

I am finding the following problem trying to save a new document into Firestore database by calling the related POST API and manually setting the document ID.
I am using Python but I suppose that the problem is not related to the language.
I try to explain what I have done and what is not working. My first attempt (that works but automatically set the document ID on Firestore) was:
First of all, I created this JSON document that will be the payload of my API:
# Convert the record to a dictionary
doc = {
'fields': {
'surname': {'stringValue':record[2]},
'firstName': {'stringValue':record[1]},
'socialSecurityCode': {'stringValue':codici_fiscali_list_as_string},
'city': {'stringValue':record[4]},
'personalPhone': {'stringValue':record[5]},
'personalPhone2': {'stringValue':record[6]},
'personalEmail': {'stringValue':emails_list_as_string},
'pazPres': {'stringValue':record[7]},
'pazNotes': {'stringValue':record[8]},
'pazMemo': {'stringValue':record[9]},
'isArchived': {'booleanValue':isArchived},
'isMigrated': {'booleanValue':True},
#'decomposition_keyword_search_list':{'arrayValue':{'values':decomposition_keyword_search_list}}
"decomposition_keyword_search_list":{
"arrayValue":{
"values":[
]
}
}
}
}
then I perform the API call by these lines:
api_endpoint = 'https://firestore.googleapis.com/v1/projects/MY-PROJECT-NAME/databases/(default)/documents/test/'
response = requests.post(api_endpoint, json=doc)
It works fine and it put the expected document into my test collection. But in this way, the ID was automatically generated by Firestore. For some reason, I have to use the content of a variable as ID (my ID must be the value of my record[0] that is a unique string)
So I tried to change the previous API endpoint in the following way:
api_endpoint = 'https://firestore.googleapis.com/v1/projects/MY-PROJECT-NAME/databases/(default)/documents/test/'+ record[0]
I expected that it creates a document using the record[0] as a document ID but it seems that I am wrong since I am obtaining the following error message:
Error saving document: {
"error": {
"code": 400,
"message": "Document parent name \"projects/MY-PROJECT-NAME/databases/(default)/documents/test\" lacks \"/\" at index 71.",
"status": "INVALID_ARGUMENT"
}
}
So, what is wrong? What am I missing? How can correctly manually set the ID of the document that I am creating calling the previous API?
Take a look at the documentation for creating documents. If you want to specify a document ID, it says you should pass that as a query parameter called documentId:
The client-assigned document ID to use for this document.
Optional. If not specified, an ID will be assigned by the service.

Querying wordpress with meta queries from Gatsby

I'm trying to fetch data from my Wordpress backend using a meta query. I'm using this plugin:
https://www.wpgraphql.com/extenstion-plugins/wpgraphql-meta-query/
I can run my query in GraphiQL IDE in Wordpress, but not in Gatsbys GraphiQL tool.
I get this error:
Unknown argument "where" on field "Query.allWpPage"
Query:
query test {
allWpPage(
where: {metaQuery: {
relation: OR,
metaArray: [
{
key: "some_value",
value: null,
compare: EQUAL_TO
},
{key: "some_value",
value: "536",
compare: EQUAL_TO
}
]
}}
) {
edges {
node {
id
uri
}
}
}
}
I've tried deleting the cache directory and rebuilding, didn't help.
And just to clarify, I have no problems running other queries and getting ACL-data and what not. The only problem I have (right now) is exposing the where argument to Gatsby.
where filter is restricted in Gatsby. Here you have a detailed list of comparators, but they are:
eq (equals)
ne (not equals)
in (includes)
nin (not includes)
lt, lte, gt, gte (less than, equal or less than, greater than, equal or greater than respectively)
regex, glob (regular expression)
elemMatch (element matches)
On the other hand, there is a list of filters available. In your case, filter is what you are looking for. Your final query should look like:
query test {
allWpPage(
filter : {uri : {ne : "" }}
) {
edges {
node {
id
uri
}
}
}
}
Of course, adapt the filter to your needs. elemMatch should work for you either.
You will need to add each condition for each property of the object you're trying to match.
Why is where restricted?
Because it belonged to Sift, a library that Gatsby was using to use MongoDB queries, where where is available. Since Gatsby 2.23.0 (June 2020) this library is not being used anymore. More details at History and Sift:
For a long time Gatsby used the Sift library through which you can use
MongoDB queries in JavaScript.
Unfortunately Sift did not align with how Gatsby used it and so a
custom system was written to slowly replace it. This system was called
“fast filters” and as of gatsby#2.23.0 (June 2020) the Sift library is
no longer used.

Hasura object permission based authorization

I am trying to set a "Row Select" permissions on Hasura. I have a (simplified for brevity) Data Model like below
User
id: UserID
App
id: AppID
App Permissions
user_id: User ID
app_id: App ID
permissions: [ ENUM: Admin, View, Owner ]
Feed
app_id: AppID
feed_data: Some Feed Data
Now, I wish to query all Feed for an authenticated user. The query can be of the form
GET all apps, for which the authenticated user has view permissions
query MyQuery {
feed(limit: 10) {
app_id
feed_data
}
}
GET apps with app_id in the query filter for which the authenticated user has view permissions
query MyQuery {
feed(limit: 10, where: {app_id: {_in: [1, 2]}}) {
app_id
feed_data
}
}
Since feed table does not have user_id information directly in it, I can not use X-Hasura-User-Id attribute directly against feed table. I also tried to use _exists relation against the app_permission table, but I am unable to put app_id filter in the permission clause.
{
"_exists": {
"_where": {
"user_id": {
"_eq": "X-Hasura-User-Id"
}
},
"_table": {
"schema": "public",
"name": "app_permission"
}
}
}
I am not really sure how to proceed with such data modelling with Hasura. Any help is appreciated. Thanks.
Since you dont have a direct relationship, I think you can query via appPermissions Table instead of directly querying feeds table.
When you create a feeds table with appId as foreign key relationship, Hasura lets you track this relationship as shown below
This way you can make nested graphQL queries to appPerms table as shown below
query GetUserFeeds {
test_appPerms {
id
userId
feeds(limit: 10) {
app_id
id
feed_data
}
}
}
Another thing I'd like to suggest is that you could try is by using a session variable like x-hasura-app-id along side a x-hasura-role and build your permissions around that.
https://hasura.io/docs/latest/graphql/core/auth/authorization/roles-variables.html

DynamoBD/Amplify non-negative field and field validation on mutations

I am new to AWS in general, I am building a relatively simple application with Amplify, but I've used Google Firebase before. My question is: Is there a way to set a constrain for a field to be non-negative? I have an application that does transactions and I don't want my balance to be negative. I just need a simple error/exception. Is it possible to set a field constraint in DynamoDB that says "This field should be >= 0"?.
I also checked if it was possible to do it in the VTL amplify generated resolver of my graphql mutation, and indeed it is possible to set some constraints, But somehow it allows the operation and crashes on the next one (when the balance on the DB is already < 0, like if it checks it before the update). I tried saying something like "current_balance - transaction >= 0" but I couldn't get it to work.
So it seems that the only way is to create a custom lambda resolver that does the various checks before submitting the mutation to DynamoDB. I haven't tried it yet but I don't understand how I can do a check on the current balance (stored in the DB) without doing a query.
More in general is it even possible to validate fields (even with simple assertions like non-negative) on amplify/dynamoDB? Moving to another DB like Aurora would help?
Thanks for you help
DynamoDb supports conditional updates which allow an update to be applied when the given condition is met. You can set the condition current_balance >= cost for your update.
However, the negative balance is not the main problem. What you should address is how to prevent other requests from updating the same current_balance at the same time, or in short, race conditions on current_balance. In order to deal with that, you also need a conditional update whose condition is "current_balance = initial_balance". The initial_balance is, I guess, what you get from DynamoDB at the very beginning of the purchase process.
Sample VTL code
#set( $remaining_balance = $initial_balance - $transaction_cost )
#if( $remaining_balance < 0 )
$util.error("Insufficient balance")
#end
{
"version" : "2018-05-29",
"operation" : "UpdateItem",
"key": { <your-dynamodb-key> },
"update" : {
"expression" : "SET current_balance = :remaining_balance",
"expressionValues" : {
":remaining_balance" : $util.dynamodb.toNumberJson($remaining_balance)
}
},
"condition": {
"expression": "current_balance = :initial_balance",
"expressionValues" : {
":initial_balance" : $util.dynamodb.toNumberJson($initial_balance)
}
}
}

How do I make a Hasura data API query to fetch rows based on the length of the their array relationship's value?

Referring to the default sample schema mentioned in https://hasura.io/hub/project/hasura/hello-world/data-apis i.e. to the following two tables:
1) author: id,name
2) article: id, title, content, rating, author_id
where article:author_id has an array relationship to author:id.
How do I make a query to select authors who have written at least one article? Basically, something like select author where len(author.articles) > 0
TL;DR:
There's no length function that you can use in the Hasura data API syntax right now. Workaround 1) filter on a property that is guaranteed to be true for every row. Like id > 0. 2) Build a view and expose APIs on your view.
Option 1:
Use an 'always true' attribute as a filter.
{
"type": "select",
"args": {
"table": "author",
"columns": [
"*"
],
"where": {
"articles": {
"id": {
"$gt": "0"
}
}
}
}
}
This reads as: select all authors where ANY article has id > 0
This works because id is an auto-incrementing int.
Option 2:
Create a view and then expose data APIs on them.
Head to the Run SQL window in the API console and run a migration:
CREATE VIEW author_article_count as (
SELECT au.*, ar.no_articles
FROM
author au,
(SELECT author_id, COUNT(*) no_articles FROM article GROUP BY author_id) ar
WHERE
au.id = ar.author_id)
Make sure you mark this as a migration (a checkbox below the RunSQL window) so that this gets added to your migrations folder.
Now add data APIs to the view, by hitting "Track table" on the API console's schema page.
Now you can make select queries using no_articles as the length attribute:
{
"type": "select",
"args": {
"table": "author_article_count",
"columns": [
"*"
],
"where": {
"no_articles": {
"$gt": "0"
}
}
}
}

Resources