Postgres invalid input error on SELECT statement - node.js

I am using Supabase as my DB.
I have users table with id field being populated with uuid_generate_v4().
I also have table bank_ao with foreign key bankId pointed to users.id.
When I do following:
const uuid = req.params.id //this 100% works correctly and returns UUID every time!
await supabase
.from("bank_ao")
.select()
.eq("bankId", uuid);
I get this error
{"code":"22P02","details":null,"hint":null,"message":"invalid input syntax for type bigint: \"914eda70-2ecf-49b0-9ea6-87640944ed16\""}
I don't have BIGINT field in my entire DB. I have checked 100x.
I also tried to add ' around my uuid variable, but it still doesn't work.
Any ideas?
Could this be some error specific to Supabase?

You need to cast the UUID into text to compare it there:
const uuid = 'e1bee290-45d1-4233-ad96-b9924288d64c'
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
const { data: ret, error } = await supabase
.from('bank_ao')
.select()
.eq('bankId::text', uuid);
console.log(ret);
Assuming table format as:
Output:
[
{
bankId: 'e1bee290-45d1-4233-ad96-b9924288d64c',
created_at: '2023-02-08T16:03:21.064501+00:00',
foo: 'bar',
bar: { bar: 'foo' }
}
]
Please note that for using BigInt in Javascript safely, then you can check it here (similar approach).

The problem was the following.
Before I used UUID as my id column value, it used to be BIGINT. When I changed it, it didn't change in cache, or some other type of memory. So, it threw an error.
I fixed it by re-creating entire database (I tried with table first, but it didn't work).
I have read online that if this is local version of Supabase you can just restart Postgres and it works fine (https://github.com/supabase/supabase/discussions/11891).

Related

Apollo Cache ignoring Field Alias as key (MockedProvider)

I am seeing some differences in behaviour between ApolloProvider and MockedProvider and it's throwing an error in testing.
Assuming I have the following query:
query {
Author {
id: authorID
name
}
}
In ApolloProvider this query creates entries in the Apollo Cache using the field alias as the key, each Author in the cache has an id. Therefore, Apollo can automatically merge entities.
When using MockedProvider, this is not the case. When I mock the following response:
const mockResponse = {
data: {
Author: {
id: 'test!!',
name: 'test'
},
},
}
I get the following error:
console.warn
Cache data may be lost when replacing the Author field of a Query object.
To address this problem (which is not a bug in Apollo Client), define a custom merge function for the Query.Author field, so InMemoryCache can safely merge these objects:
existing: {"authorID":"test!!"...
So the exact same query in ApolloProvider uses id (field alias) as the key and in MockedProvider it just adds authorID as another field entry. It ignores the field alias and has no key.
Obviously now nothing is able to merge. My first guess is that it's because the MockedProvider does not have access to the schema so it doesn't know that authorID is of type ID? Or am I way off?
One thing that's really weird to me is that my mockResponse doesn't even provide an authorID. My mockResponse is { id: "test!!" } but the cache shows an entry for {"authorID":"test!!"}, so it's somehow 'unaliased' itself.
I'm really struggling to understand what is happening here. Any insight at all would be enormously useful.

How do I use pgcrypto with knex inside a .select statement? (Postgres database)

I'm currently using knex to connect my node.js sever to a postgres database and I have started using pgcrypto to encrypt some of my data. I am a bit late to the game with encrypting my data, so I have several queries I'll need to update, and am looking for the most efficient way to not only swap over my queries, but to actually query the database. When I try to implement the PGP_SYM_DECRYPT directly inside the knex.select() query, I get an error saying the user can't be found. However, if I use the knex.raw() query, I can get it to work. Is there any way to use the PGG_SYM_DECRYPT inside the .select() query, or perhaps a way to pass the secret key alongside of the query so it will automatically decrypt any encrypted columns?
Example WORKING code:
const user = await knex("n_user AS u")
.where({
"u.uuid": uuid,
"su.site_id": site.id
})
.first()
.join("site_has_user AS su", { "su.user_id": "u.id" })
.select(
"u.id",
"u.uuid",
"u.mobile_number",
"u.email",
"u.first_name",
"u.last_name",
"u.department",
// "u.note", the note is the encrypted data
"u.disabled",
"su.role"
)
.select(
knex.raw(
`PGP_SYM_DECRYPT(u.note::bytea, '${process.env.SECRET_KEY}') as note`
)
);
Example DESIRED code (or some other variant):
const user = await knex("n_user AS u")
.where({
"u.uuid": uuid,
"su.site_id": site.id
})
.first()
.join("site_has_user AS su", { "su.user_id": "u.id" })
.select(
"u.id",
"u.uuid",
"u.mobile_number",
"u.email",
"u.first_name",
"u.last_name",
"u.department",
`PGP_SYM_DECRYPT(u.note::bytea, '${process.env.SECRET_KEY}') as note`,
"u.disabled",
"su.role"
);
Any thoughts?
You can add raw snippet inside select like this:
.select(
"u.id",
"u.uuid",
"u.mobile_number",
"u.email",
"u.first_name",
"u.last_name",
"u.department",
knex.raw("PGP_SYM_DECRYPT(??::bytea, ?) as note", ['u.note', process.env.SECRET_KEY]),
"u.disabled",
"su.role"
);
In raw syntax ?? is identifier replacement and ? is value binding so that secret key is passed to driver safely as binding without trying to interpolate it directly to SQL string.

How to pass date as an input to SQL Server query in node

I am using node-mssql and my function goes like this:
const getPoliciesDue = async (userId, toDate) => {
const db = await sql.connect(config) // const sql = require('mssql'), config = {config for my DB}
const request = db.request()
.input('userId', sql.VarChar, userId) // userId is a string
.input('toDate', sql.Date, toDate) // toDate is a javascript Date() object
const result = await request.query(
'SELECT policyNumber, holderId, ... FROM Policies WHERE Policies.userId = #userId AND Policies.toDate <= #toDate'
)
return result.recordset
}
I want to get all the policies which are expiring before a certain date belonging to a certain user.
But when I run this exact query, I get the error
Must declare the scalar variable #userId
I removed #userId from the WHERE clause and put '#toDate' (quotes around the variable). Now I get an error
Conversion failed when converting date and/or time from character string
The documentation says input() accepts the Date() object. I have tried passing date object as well as a string in YYYY-MM-DD format, but with no avail. Passing a string in YYYY-MM-DD format works for an INSERT query, but not for a SELECT query. How am I supposed to run my query?
Note I can't run the query in a single line, like
db.request().input().query()
because there is another input which will later go in conditionally.
Okay, a huge oversight on my part and sincere apologies to those who tried to find an answer. I found out that I was running the query() method on the wrong object. I was running the query method on db object whereas I should have run it on the request object. The code works perfectly after calling the method on the right object.

Not able to access the data inside of an object

I am fetching id column value from database for a particular email. In this case I am passing email and want to get primary key i.e id. This operation is successful as I get object which contains Object with the right and expected result. However I am not able to access the object.
I am receiving object like this:
[ UserInfo { id: 21 } ]
And I am not able to access id part of it.
I am using node.js, postgres for database and typeorm library to connect with database.
const id = await userRepo.find({
select:["id"],
where: {
email:email
}
});
console.log(id)
This prints the above object.
The id I am getting is right. But I am not able to retrieve the id part of the object. I tried various ways for e.g.
id['UserInfo'].id, id.UserInfo.
Please help me in accessing the object I am receiving
Typeorm .find() returns an array of objects containing entries corresponding to your filters, in your case, all entries with an email field corresponding to the email you specified.
Because the result is an array, you can access it this way:
const records = await userRepo.find({
select: ['id'],
where: {
email,
},
})
console.log(records[0].id)
You could also use the .findOne() method, which returns a single element and might be a better solution in your case :)
When you are putting a field in the select part select:["id"], you are only retrieving this part of the database.
It is like your query was this: select id from userRepo where email = email
and you need to put * in the select part to retrieve all the information:
const id = await userRepo.find({
select:["*"],
where: {
email:email
}
});

Knex primary key auto increment

I'm using knex to create a simple table in postgres database:
function up(knex, Promise) {
return knex.schema.createTableIfNotExists('communities', (table) => {
table.increments('id').primary().unsigned();
table.string('name', 255).notNullable();
table.string('slug', 100).notNullable();
table.timestamp('createdAt').defaultTo( knex.fn.now() );
table.timestamp('updatedAt');
});
};
function down(knex, Promise) {
return knex.schema.dropTableIfExists(tableName);
};
module.exports = {
tableName,
up,
down
}
My problem is that table.increments('id').primary() creates a primary key that for default value has nextval('communities_id_seq'::regclass) and I can't do an insert without an id (even in raw sql).
Does anyone know how to make the id increment by default?
In js:
table.increments()
Output sql:
id int unsigned not null auto_increment primary key
check this out for more information
My problem was that the value for id was an empty string and not undefined or null, so that was braking the constraint for integer as data type.
Hope it helps!
A bit late to the party but I was having this issue with the same use case. However my solution was I didnt have all the correct permissions granted to my sequences, only my tables when i ceated the DB.
So something along the lines of "GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO PUBLIC"

Resources