GORM model foreign key to different Postgres schema - postgresql

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?

Related

Is there any way to create foreign key from different schemas?

I have an application where I am separating data with schemas where I have one table common in all schemas. lets say I have one public schema which is an admin schema and other schemas such as a,b,c,...,etc which are user schema. And all schemas have one common table T and all users can create entries in this T table and there are some entries which can only be created by admin user and all other users will use that rows.
so how I will achieve this.
I have two onptions in my mind
I will create T table in every schema and when ever admin adds new entry I will add that in all other schemas.
I will create T table in public schema and will add foreign key from that schema in other schema.
note: Schemas are dynamic and they are created run time and I am using postgres, Nestjs and sequelize-typescript

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 different schema relation for tables

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"
}

Create Postgres FDW using the postgres super user yet have read only access to the remote schema

I am trying to create an FDW using the postgres super user credentials using the following steps -
My super user is postgres
CREATE SERVER testfdw
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host '10.10.10.171', dbname 'testdb', port '5432', fetch_size '50000');
I have created a read only remote user called testdb_read_only_user on testdb and granted read only privileges to all tables and sequences and functions in there
I now create a user mapping for my local db super user postgres
CREATE USER MAPPING
FOR postgres
SERVER testfdw
OPTIONS (user 'testdb_read_only_user', password 'testpasswrd')
Then I run IMPORT FOREIGN SCHEMA public FROM SERVER testfdw INTO test_local_schema;
Now when I try to create a new foreign table into test_local_schema using the postrges super user, I am still able to create one, but the actual behaviour I expect is a permission denied error and my user mapping is based on the read only user I created on the Remote DB
Am I missing something here. Please guide.
The foreign schema test_local_schema is owned by postgres(Superuser) and PostgreSQL treating it as a local schema(on target) gives you option to create a new table, Now when you are creating a new foreign table in test_local_schema postgres will check below constraints
The name of the foreign table must be distinct from the name of any other foreign table, table, sequence, index, view, or materialized view in the same schema.
To create a foreign table, you must have USAGE(read) privilege on
the foreign server, as well as USAGE privilege on all column
types used in the table
CREATE privilege on the target schema.
As your user mapping has read-only user in source database you should be able to fetch data in order to create a foreign table in target database, however whenever you will update and insert new data it will give you error as testdb_read_only_user is not having any update/insert privileges.
https://www.postgresql.org/docs/9.5/sql-createforeigntable.html
https://www.postgresql.org/docs/9.5/sql-importforeignschema.html

Postgres Foreign-key constraints in non public schema

I have a question regarding constraints on custom schemas.
My app creates a new/separate schema for each clients corresponding with clients' name (i.e .clienta, clientb,...). Some of the tables have a foreign-key constraints but, they don't work on schemas other than the default public schema. For example, let's say there is schema called clienta and it has projects and tasks tables, model Task has a belongsTo(models.Project) association (i.e projects table primary_key is a foreign_key for table tasks. The issue starts here: when trying to create a record in table tasks there comes an error saying foreign key violation error... Key (project_id)=(1) is not present in table "projects... even though projects table has the respective record with id = 1. I am wording if this is a limitation of sequelize library itself or am I missing something in the configs?
Sequelize config
"development": {
"database": "my_app",
"host": "127.0.0.1",
"dialect": "postgres",
"operatorsAliases": "Sequelize.Op",
"dialectOptions": {
"prependSearchPath": true
},
"define": {
"underscored": true
}
}
Example of create function:
models.Task.create({...args}, { searchPath: 'clienta' })
N.B Everything works as expected in public schema.
The sync method API lists two options relating to DB-schema:
options.schema - schema the table should be created in
options.searchPath - optional parameter to set searchPath (Postgresql)
When using schemas other than the default and an association between Models has been created (using for instance belongsTo), it is important to set the searchPath to hold the name of the schema of the target table. Following the explanation in search_path in postgresql, not specifying the searchPath will have the constraint referring to a table (if it exists) in the default schema (usually 'public').