Prisma NodeJS: Include ID in query - javascript

Model:
model Foo {
id Int #id #default(autoincrement())
name String
bar Bar?
}
model Bar {
id Int #id #default(autoincrement())
name String
foo Foo #relation(fields: [fooId], references: [id])
fooId Int
}
Node Code:
import { PrismaClient } from "#prisma/client";
async function main() {
let client = new PrismaClient();
let foo = client.foo.findFirst( ??? )
};
main()
What goes in the ??? to get an object that includes both Foo and Bar's IDs (as well as all the other fields once the model gets bigger)?
Note that if possible, it shouldn't use select since in a larger model I'd need to list out every field including id which I am not up to do. If there isn't any alternative other than raw SQL, let me know.

As of the documentation:
const result = await prisma.user.findUnique({
where: {
id: 42,
},
})
So, in your case:
client.foo.findFirst( ??? )
Would become:
client.foo.findFirst({
where: {
id: yourvaluehere
}
})

Related

How to serialize enum in borsh-js

Trying to serialize an object in Rust and deserialize it in JS
We got 000100000031 hash, after serialization this:
pub enum Service {
Stackoverflow,
Twitter,
Telegram,
}
pub struct ServiceId {
pub service: Service,
pub id: ExternalId,
}
When trying to deserialize in JS use this:
const Service = {
Stackoverflow: 0,
Twitter: 1,
Telegram: 2
}
class ServiceId {
constructor(service, id) {
this.service = service
this.id = id
}
}
const value = new ServiceId(Service.Stackoverflow, userId)
const schema = new Map([
[ServiceId,
{ kind: 'struct', fields: [['service', 'u8'], ['id', 'string']] }]
]);
After deserialization, we got this, but it is incorrect because we have an object inside an object and a redundant id parameter:
ServiceId { service: { service: undefined, id: '1' }, id: undefined }
Firstly it could be because in Rust we have enum type, so how we can use enum in borsh-js.
Second if not, why do we have an incorrect results?
It is hard to understand from documentation, but you need to create your class like this and all will be okay.
class ServiceId {
constructor({ service, id }) {
this.service = service
this.id = id
}
}
new ServiceId({ service: 'lol', id: 'kek' })
So you need to pass your params as object.

how to find post by using findUnique in prisma with post id and prodCode

I want to find only one post matching by post id and prodCode
below is my query code. It doesn't work.
If i change findUnique to findFirst. it works.
const post = await client.post.findUnique({
where: {
AND: [
{ id: postId },
{
product: {
prodCode,
},
},
],
},
});
prisma model
model Product {
id Int #id #default(autoincrement())
prodName String
prodCode String #unique
posts Post[]
holdings Holding[]
proposes Propose[]
}
model Post {
id Int #id #default(autoincrement())
user User #relation(fields: [userId], references: [id])
userId Int
product Product #relation(fields: [productId], references: [id])
productId Int
title String
content String
createdAt DateTime #default(now())
}
Since Post.id is unique, you don't need to filter by prodCode as well. You could just query the post record with the needed id and then check if the connected product has the right prodCode.
I would just do this:
const post = await prisma.post.findUnique({
where: {
id: postId
},
include: {
product: true
}
});
if (post.product.prodCode === prodCode) {
// No result for desired query
} else {
// "post" variable contains result of desired query
}

How can I access the auto-created document ID when creating a new Firestore document in Angular?

I am trying to return the document id when I create it. Since Firebase functions are async the return value is not completed until the query is done. How can I prevent this so I can wait to get the value when the query is done?
This function create the document is located in a service:
public makeDoc(title: string, score: number): any{
const fields = {
title: title,
score: number
}
this.db.collection('saved').add(fields)
.then(function(ref) {
console.log(ref.id);
return ref.id;
})
}
I call this from a function which is located in a component:
onCreate() {
const str = this.createService.makeDoc(this.title, this.score);
console.log(str);
}
Try following:
const fields = {
title: title,
score: number
}
var newFieldsRef = this.db.collection('saved').push();
this.db.collection('saved').child(newFieldsRef).set(fields);
var id = newFieldsRef.toString();
You don't want to prevent waiting until the query is done, you should embrace the use of promises here.
First, if you haven't, make sure you import the firestore namespace in the service:
import { firestore } from 'firebase';
Now, for your service:
I had to slightly change your makeDoc method as the fields object wasn't being created in a valid way (e.g. reusing the number type):
public makeDoc(titleParam: string, scoreParam: number): Promise<firestore.DocumentReference> {
const fields = {
title: titleParam,
score: scoreParam
};
return this.db.collection('saved').add(fields);
}
This now returns a Promise<DocumentReference> which, when resolved, the reference will point to the created document.
Now, the call to it in onCreate looks like:
onCreate() {
this.createService.makeDoc('myTitle', 123)
.then((ref) => { console.log(ref.id); })
.catch((err) => { console.log(err); });
}
And this will log the id as soon as it is available.

Typescript factory class using logic

I have a typescript class inheriting another one. I would like to create a factory class that creates an object of one or the other using basic logic, but it is not working.
This is a basic class for a Customer:
class Customer {
static member = true;
id:string;
static c_type = "Basic Customer";
makeTransaction():string {
var transaction_id = Math.random().toString(36).substr(2, 9);
console.log(this.constructor.toString().split ('(' || /s+/)[0].split (' ' || /s+/)[1]);
return transaction_id;
}
constructor(public name:string, public dob:string) {
this.id = Math.random().toString(36).substr(2, 9);
}
}
This class extends customers to create a VIP customer:
class VIPCustomer extends Customer{
vip_num:string;
vip_discount:number;
static c_type = "VIP Customer";
constructor(public name:string, public dob:string) {
super(name, dob);
this.vip_num = Math.random().toString(36).substr(2, 9);
}
}
The customer creator is intended to create either a VIP customer or regular customer based on a string comparison, but it is not working.
class CustomerCreator {
static create(event: {name:string; dob: string}, type:string) {
console.log('Log type' + typeof type);
if (type === 'Basic') {
console.log('basic customer created');
return new Customer(event.name, event.dob);
}
if (type === 'VIP') {
console.log('basic customer created');
return new VIPCustomer(event.name, event.dob);
}
}
}
console.log(Customer.c_type);
console.log(VIPCustomer.c_type);
const customer_1 = CustomerCreator.create({name:'Pii', dob:'03/19'}, 'VIP');
var customer_2 = CustomerCreator.create({name:'Matthew', dob:'12/70'}, 'Basic');
//accessing an attribute
console.log(customer_1.name);
console.log(customer_1.id);
//console.log(customer_1.vip_num)
If you uncomment the last print statement, the code does not compile. The print statements also indicate that a basic customer is being created for both the customers 1 and 2, despite the string comparison. Where am I going wrong?
Typescript only has type info of compiling time, but not type info only known in run time.
The return type of CustomerCreator.create is Customer|VIPCustomer which is narrowed down to Customer so everything return from that function is recognized to ts compiler as Customer . That's the whole point of Factory pattern, that your code rely on interface but not class
If you really want to let compiler know what exact type of what CustomerCreator.create returns, you could try following code
type CreatorResult = {
Basic: Customer,
VIP: VIPCustomer
}
class CustomerCreator {
static create<T extends 'Basic'| 'VIP'>(event: {name:string; dob: string}, type:T): CreatorResult[T] {
although this is not recommended
Your solution is not working because the create factory method always returns the type Customer as VIPCustomer is also derived from Customer. Also, your create function not only returns just Customer but Customer | undefined because you do not have a default case (when type is neither Basic or VIP). I would just create multiple factory methods for each type of customer. In this case of my example there is almost no shared piece of code or extra processing, the factory pattern is rendered useless.
class CustomerCreator {
static create(event: { name: string; dob: string }) {
return new Customer(event.name, event.dob);
}
static createVip(event: { name: string; dob: string }) {
return new VIPCustomer(event.name, event.dob);
}
}
console.log(Customer.c_type);
console.log(VIPCustomer.c_type);
const customer_1 = CustomerCreator.createVip({ name: 'Pii', dob: '03/19' });
var customer_2 = CustomerCreator.create({ name: 'Matthew', dob: '12/70' });
console.log(customer_1.name);
console.log(customer_1.id);
console.log(customer_1.vip_num)

Reference equality for container objects

For a specific application we are storing id's of objects in specific classes. For example, a "product" object would have it's string id stored in a "ProductId" object. Likewise a "user" object would have it's string id stored in a UserId object (see example code below).
class Product {
id: ProductId;
price: number;
...
}
class User {
id: UserId;
name: string;
...
constructor(id: UserId, name: string) {
this.id = id;
this.name = name;
...
}
}
class ProductId {
id: string;
constructor(id: string) {
this.id = id;
}
}
class UserId {
id: string;
constructor(id: string) {
this.id = id;
}
}
One issue with this approach is that storing objects in a Map and then trying to retrieve them (see below code) does not work because two UserId's with the same underlying id do not compare equal with ===.
const users = new Map<UserId, User>();
const user = new User(new UserId('8753098'), 'John');
users.set(user.id, user);
console.log(users.get(new UserId('8753098')); //undefined
It seems that javascript does not have operator overloading, or has no way of overriding the equality function.
I have also thought of working with a global map, and create Id's with a static method :
class UserId {
private id: string;
constructor(id: string) {
this.id = id;
}
static userIds = new Map<string, UserId>();
static fromString(id: string) {
let userId = userIds.get(id);
if (userId === undefined) {
userId = new UserId(id);
userIds.set(id, userId);
}
return userId;
}
}
But that has a potential memory leak because all objects are retained in the map and never released.
Does anyone have a solution for this ?
Does anyone have a solution for this ?
Instead of class UserId just do a type type UserId = string.
More
If you are concerned about structural equality and would prefer nominal typing you can add a brand using an enum as shown here
enum UserIdBrand {}
type UserId = UserIdBrand & string;

Categories