gorm different schema relation for tables - postgresql

To further explain my problem I have a database in postgreSQL. With the intent of the database to look cleaner I split most of the tables in between two schema-s one for the "users" and a second for the so called "teams". As it's expected I've created a many to one relation between the teams.team table and the users.user table by giving the teamID inside the user table. I'm writing the backend for the current software in GoLang and decided to use Gorm as way to handle the database. I've gotten somewhat the hang of gorm and figured out how to use schema-s and to test that Gorm can handle my database solution I decided with the structures, I've created to represent the tables, to create again all my tables in the db.
For the different schema-s I've had to make different connections and specify that I want them for the specific schema and since I have to write that there's a connection to Team inside User it thinks it's in the same schema
type User struct {
gorm.Model
FirstName string
LastName string
Email string
ElsysEmail string
Mobile string
Password string
InfoID uint
Info Info
SecurityID uint
Security Security
RoleID uint
Role Role
TeamID uint
Team Team
LastLogin time.Time
}
For anyone having a problem with creating tables inside a schema here's my solution:
dsn := "host=localhost user=postgres password=password dbname=ht9 port=5432 sslmode=disable"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{NamingStrategy{TablePrefix: "schemaName."}})
if err != nil {
log.Fatal(err)
}
disclaimer : my problem is almost identical to this one - GORM model foreign key to different Postgres schema - but no one's answered it yet

Try implementing the Tabler interface. as follow
type AppUser struct {
global.GVA_MODEL
Username string `json:"userName" gorm:"index;comment:user'sname"`
}
func (u *AppUser) TableName() string {
return "app.app_users"
}

Related

Prisma - How to reference SQL view in schema

I am designing a database schema for a multi-tenant project where a single user might have multiple "profiles", one for different tenants. I am using Supabase to provide a Postgres database along with some of their other BaaS features and hoping to use Prisma to help me manage the schema, relations, and migrations.
Supabase provides their own auth service, leveraging their auth.users table (in the auth schema). I want/need my public.profiles table to have a 1-n relation with auth.users so I can link my user to all of their profiles.
Is there a way I can define this in my schema.prisma file? I have tried manually creating a VIEW in the database and then defining a model for it, but when I try to apply my other Prisma schema changes (npx prisma db push or npx prisma db migrate dev) I get an error that the view/model already exists.
When database is initialized, I create the Auth SQL view in the public schema.
CREATE VIEW "Auth" AS SELECT id, email, role, created_at, updated_at, invited_at from auth.users;
Then in my Prisma schema I replicate the model. This seems to be the approach if you are using introspection, but I want Prisma to manage the schema, not the other way around.
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// SQL view in public schema of Supabase "auth.users" table
model Auth {
id Int #unique
email String
role String
createdAt DateTime #map("created_at")
updatedAt DateTime #map("updated_at")
invitedAt DateTime #map("invited_at")
profiles Profile[]
}
model Profile {
id Int #id #default(autoincrement())
// This relation should reference the "auth.users" table
user Auth #relation(fields: [uid], references: [id])
uid Int
client Client #relation(fields: [clientId], references: [id])
clientId Int
firstName String
lastName String
}
model Client {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
updatedAt DateTime #default(now())
name String
type String
preferences Json
profiles Profile[]
}
Essentially, I need to know how I can create a relation to some portion of the schema that Prisma does not control. Can I define a reference-only model? Or a model that should be ignored during push or migrate operations? Can I define an explicit table name in the model relation definition?
There is this issue that talks about adding more support for views, but it's unclear if/when anything will happen. I'm wondering if anyone has a different solution. If this won't work I may just need to look into using something like NextAuth so I can fully manage the auth schema, but I'd prefer not to rebuild an auth system if I can help it.
You could create a public.users table via Prisma and add a Postgres trigger to duplicate the auth.users data to your public schema anytime a user signs up:
/**
* This trigger automatically creates a user entry when a new user signs up via Supabase Auth.
*/
create function public.handle_new_user()
returns trigger as $$
begin
insert into public.users (id, full_name, avatar_url)
values (new.id, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url');
return new;
end;
$$ language plpgsql security definer;
create trigger on_auth_user_created
after insert on auth.users
for each row execute procedure public.handle_new_user();
Does that approach work for you?

GORM model foreign key to different Postgres schema

I have 2 separate Go APIs that connect to the same Postgres database into different schemas. Each user has all access to all schemas.
In the first API I have the User model with schema1.Users table
In the 2nd I have the Task model with schema2.Tasks table
type User struct {
gorm.Model
}
type Task struct {
gorm.Model
CreatedBy uint
User User `gorm:"foreignKey:CreatedBy;references:User"`
}
When I try to run the 2nd API, the migrations create a Users table in schema2 and connects the foreign key there.
If I use the line below I get an error
User User `gorm:"foreignKey:CreatedBy;references:schema1.User"`
[error] invalid field found for struct github.com/xyz/models.Tasks's field User: define a valid foreign key for relations or implement the Valuer/Scanner interface
Any ideas how to connect the different schemas?

Postgres / TypeORM - multiple joins. How should I format the query?

I am building a backend microservice which uses postgres as DB and TypeORM (NodeJs) library to manage connections with it.
Imagine that my db contains 3 tables / entities.
User table (primary column is - id)
Profile table (primary column id, then foreign key user_id pointing to user tables id column)
There might be multiple profile rows linked to one user
Experience table (primary column id, then foreign key profile_id column pointing to profile table id column)
There might be multiple experience rows linked to one profile
a) Can I perform one complex query to get profile row & all experience rows linked to it?
getFullProfile(profileId: number) {
return this.profileEntityRepository.createQueryBuilder('profile')
.where('profile.id = :profileId', { profileId })
.innerJoinAndMapMany('profile.experience', ExperienceEntity, 'experience', 'experience.id = profile.id')
.getOne();
}
Sadly this does not return any results (it does if I comment out innerJoinAndMapMany line).
Any suggestions? It doesn't have to be TypeORM api based answer, simple plain query would be sufficient.
Thanks!
Ok, I resolved it.
I changed the typeORM query to this:
getFullProfile(profileId: number) {
return this.profileEntityRepository.createQueryBuilder('profile')
.leftJoinAndSelect('profile.experiences', 'experience')
.where('profile.id = :profileId', { profileId })
.getOne();
}
To have this working I also needed to add OneToMany column in profile entity which looks like this:
#OneToMany(type => ExperienceEntity, experience => experience.profile)
experiences: ExperienceEntity[];
This doesn't create a column 'experiences' in the table, but is rather needed for TypeORM to understand the situation.

Automigrate in GORM database adds unwanted fields to SQL table

When I create my tables in the gorm database, it adds columns to the table that I don't want. I'm not sure how it's adding these extra fields. This causes me to run into an error that says, "pq: null value in column "user_id" violates not-null constraint". "user_id" is the unwanted column that gets added. I'm using gorm and postgreSQL.
I have a many to many relationship for my two tables. My first table is created properly and my second table, stores, is created with the provided fields plus two unwanted fields: "user_id" and "stores_id". I've tried removing the many to many relationship to see if that was the issue, I've tried dropping the tables and recreating them with different fields. Regardless, I have not been able to get rid of the two extra columns.
The first (working) table:
type User struct {
gorm.Model
ID int `json:"u_id"`
Name string `json:"u_name"`
Stores []Store `gorm:"many2many:stores;" json:"stores"`
}
When I execute '\d users', I get the following columns: id, created_at, updated_at, deleted_at, name.
The second (problematic) table:
type Stores struct {
gorm.Model
ID int `json:"s_id"`
NUM int `gorm:"unique" json:"s_num"`
Users []User `gorm:"many2many:user" json:"users"`
}
When I execute '\d' stores, I get the following columns: user_id, vehicle_id, id, created_at, updated_at, deleted_at, num.
I'm executing the creation of these tables through the following code:
db.AutoMigrate(&User{})
db.AutoMigrate(&Store{})
On another note, if I add gorm:"primary_key";auto_increment" to my ID values in my structs, I get the error "pq: column "user_id" appears twice in primary key constraint". I was able to get around this by removing the primary_key and auto_increment attributes, running AutoMigrate() and then adding it back in and running AutoMigrate() again - this was totally fine and working.
I've also tried manually inserting a user_id and store_id. This works fine, except that I'd have to generate new ones every time because they require uniqueness. I understand that the error "pq: null value in column "user_id" violates not-null constraint" is caused by the fact that I'm not providing a user_id or store_id when I'm creating my store. I'm simply confused why a user_id and store_id column is being generated at all, and I'm hoping I can fix that.
This is what gorm.Model looks like
type Model struct {
ID uint `gorm:"primary_key"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time
}
When we call gorm.Model inside a struct, it means we are add default fields of gorm.Model in our current struct.
type Stores struct {
gorm.Model
....
so your user model will look something like
ype User struct {
ID uint `gorm:"primary_key"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time
ID int `json:"u_id"`
Name string `json:"u_name"`
Stores []Store `gorm:"many2many:stores;" json:"stores"`
}
that error mayne due to duplicate primary_key key. try to rename ID intjson:"u_id"`` to UserID. you need to update Stores too.
Fixed the duplicate ID errors by removing gorm.Model, as #(Akshaydeep Girl) pointed out what having gorm.Model entails. As for the random 'user_id' and 'store_id' that kept automatically being added, they were being added because of the many2many gorm relationship. I was able to remove those by switching the order of migration.
func DBMigrate(db *gorm.DB) *gorm.DB {
db.AutoMigrate(&Store{})
db.AutoMigrate(&User{})
return db
}
When I dropped both tables and re-compiled/ran my project with the new order of migration, the stores table was created without the random 'user_id' and 'store_id', and the users table didn't have those either.

How to use mattes/migrate in golang?

I've been trying to use the mattes/migrate package but I can't seem to get it to actually do anything. The database runs on postgres and I interact with it through sqlx.
I've gone through the readme on github, and applied the following code:
// use synchronous versions of migration functions ...
allErrors, ok := migrate.UpSync("postgres://<my_url_string>", "./app/database/migrations")
if !ok {
fmt.Println("Oh no ...")
// do sth with allErrors slice
}
My schema is initiated like this:
//sqlx's initiated DB is imported in the database package
func SyncSchemas() {
database.DB.MustExec(schema)
}
var schema =
`CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE IF NOT EXISTS examples (
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
deleted_at text DEFAULT NULL,
id UUID PRIMARY KEY UNIQUE NOT NULL DEFAULT uuid_generate_v4()
);`
type Example struct {
ID string `json:"id" db:"id"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
DeletedAt *time.Time `json:"deleted_at" db:"deleted_at"`
}
It runs without error, but that's all it seems to be doing at the moment. Shouldn't it keep track of my schemas or something? I previously used gorm as my ORM, and there I just had to run autoMigrate() on a schema and it automatically created and applied migrations as I changed the schema. I would like the same functionality with mattes/migrate, but I can't seem to find an example or tutorial which shows how to use it.
How am I supposed to do this?
One suggestion in whenever you code in Golang is to check the errors do it in this way
if allErrors, ok := migrate.UpSync("postgres://<my_url_string>", "./migrations"); !ok {
fmt.Println("Oh no ...", ok)
// do sth with allErrors slice
}
As I don't know what is your error at least in this way you can check what your error is.