diff --git a/api/src/database.types.ts b/api/src/database.types.ts index c9294b8..e12cbaf 100644 --- a/api/src/database.types.ts +++ b/api/src/database.types.ts @@ -144,6 +144,13 @@ export type Database = { referencedRelation: "tablos" referencedColumns: ["id"] }, + { + foreignKeyName: "fk_tablo_access_tablo_id" + columns: ["tablo_id"] + isOneToOne: false + referencedRelation: "user_tablos" + referencedColumns: ["id"] + }, ] } tablo_invites: { @@ -176,6 +183,13 @@ export type Database = { referencedRelation: "tablos" referencedColumns: ["id"] }, + { + foreignKeyName: "fk_tablo_invitations_tablo_id" + columns: ["tablo_id"] + isOneToOne: false + referencedRelation: "user_tablos" + referencedColumns: ["id"] + }, ] } tablos: { @@ -216,7 +230,22 @@ export type Database = { } } Views: { - [_ in never]: never + user_tablos: { + Row: { + access_level: string | null + color: string | null + created_at: string | null + deleted_at: string | null + id: string | null + image: string | null + is_admin: boolean | null + name: string | null + owner_id: string | null + position: number | null + status: string | null + } + Relationships: [] + } } Functions: { generate_random_string: { diff --git a/sql/13_create_user_tablos_view.sql b/sql/13_create_user_tablos_view.sql new file mode 100644 index 0000000..b75a00f --- /dev/null +++ b/sql/13_create_user_tablos_view.sql @@ -0,0 +1,47 @@ +CREATE OR REPLACE VIEW user_tablos +WITH (security_invoker) +AS +SELECT DISTINCT + t.id, + ta.user_id, + t.name, + t.image, + t.color, + t.status, + t.position, + t.created_at, + t.deleted_at, + -- Access information + CASE + WHEN ta.is_admin = TRUE THEN 'admin' + ELSE 'member' + END as access_level, + ta.is_admin as is_admin +FROM tablos t +LEFT JOIN tablo_access ta ON t.id = ta.tablo_id +WHERE + ta.is_active = TRUE + AND + t.deleted_at IS NULL +ORDER BY t.position ASC, t.created_at DESC; + +-- Add comment to document the view +COMMENT ON VIEW user_tablos IS + 'View that returns all tablos accessible to the current authenticated user, including owned tablos and shared tablos with active access'; + +-- Example usage queries: + +-- 1. Get all tablos for the current user +-- SELECT * FROM user_tablos; + +-- 2. Get only tablos where user is owner +-- SELECT * FROM user_tablos WHERE access_level = 'owner'; + +-- 3. Get only shared tablos where user is admin +-- SELECT * FROM user_tablos WHERE access_level = 'admin' AND owner_id != (SELECT auth.uid()); + +-- 4. Get tablos by status +-- SELECT * FROM user_tablos WHERE status = 'in_progress'; + +-- 5. Count tablos by access level +-- SELECT access_level, COUNT(*) FROM user_tablos GROUP BY access_level; \ No newline at end of file diff --git a/ui/src/types/database.types.ts b/ui/src/types/database.types.ts index c9294b8..e12cbaf 100644 --- a/ui/src/types/database.types.ts +++ b/ui/src/types/database.types.ts @@ -144,6 +144,13 @@ export type Database = { referencedRelation: "tablos" referencedColumns: ["id"] }, + { + foreignKeyName: "fk_tablo_access_tablo_id" + columns: ["tablo_id"] + isOneToOne: false + referencedRelation: "user_tablos" + referencedColumns: ["id"] + }, ] } tablo_invites: { @@ -176,6 +183,13 @@ export type Database = { referencedRelation: "tablos" referencedColumns: ["id"] }, + { + foreignKeyName: "fk_tablo_invitations_tablo_id" + columns: ["tablo_id"] + isOneToOne: false + referencedRelation: "user_tablos" + referencedColumns: ["id"] + }, ] } tablos: { @@ -216,7 +230,22 @@ export type Database = { } } Views: { - [_ in never]: never + user_tablos: { + Row: { + access_level: string | null + color: string | null + created_at: string | null + deleted_at: string | null + id: string | null + image: string | null + is_admin: boolean | null + name: string | null + owner_id: string | null + position: number | null + status: string | null + } + Relationships: [] + } } Functions: { generate_random_string: { diff --git a/xtablo-expo/lib/database.types.ts b/xtablo-expo/lib/database.types.ts index d88e4f3..3ae0c27 100644 --- a/xtablo-expo/lib/database.types.ts +++ b/xtablo-expo/lib/database.types.ts @@ -4,212 +4,229 @@ export type Json = | boolean | null | { [key: string]: Json | undefined } - | Json[] + | Json[]; export type Database = { public: { Tables: { devis: { Row: { - client_email: string - created_at: string - date: string - due_date: string - id: string - items: Json - notes: string | null - number: string - status: Database["public"]["Enums"]["devis_status"] - subtotal: number - tax: number - terms: string | null - total: number - updated_at: string - user_id: string - } + client_email: string; + created_at: string; + date: string; + due_date: string; + id: string; + items: Json; + notes: string | null; + number: string; + status: Database["public"]["Enums"]["devis_status"]; + subtotal: number; + tax: number; + terms: string | null; + total: number; + updated_at: string; + user_id: string; + }; Insert: { - client_email: string - created_at?: string - date: string - due_date: string - id?: string - items?: Json - notes?: string | null - number: string - status?: Database["public"]["Enums"]["devis_status"] - subtotal: number - tax: number - terms?: string | null - total: number - updated_at?: string - user_id: string - } + client_email: string; + created_at?: string; + date: string; + due_date: string; + id?: string; + items?: Json; + notes?: string | null; + number: string; + status?: Database["public"]["Enums"]["devis_status"]; + subtotal: number; + tax: number; + terms?: string | null; + total: number; + updated_at?: string; + user_id: string; + }; Update: { - client_email?: string - created_at?: string - date?: string - due_date?: string - id?: string - items?: Json - notes?: string | null - number?: string - status?: Database["public"]["Enums"]["devis_status"] - subtotal?: number - tax?: number - terms?: string | null - total?: number - updated_at?: string - user_id?: string - } - Relationships: [] - } + client_email?: string; + created_at?: string; + date?: string; + due_date?: string; + id?: string; + items?: Json; + notes?: string | null; + number?: string; + status?: Database["public"]["Enums"]["devis_status"]; + subtotal?: number; + tax?: number; + terms?: string | null; + total?: number; + updated_at?: string; + user_id?: string; + }; + Relationships: []; + }; profiles: { Row: { - avatar_url: string | null - email: string | null - full_name: string | null - id: string - updated_at: string | null - website: string | null - } + avatar_url: string | null; + email: string | null; + full_name: string | null; + id: string; + updated_at: string | null; + website: string | null; + }; Insert: { - avatar_url?: string | null - email?: string | null - full_name?: string | null - id: string - updated_at?: string | null - website?: string | null - } + avatar_url?: string | null; + email?: string | null; + full_name?: string | null; + id: string; + updated_at?: string | null; + website?: string | null; + }; Update: { - avatar_url?: string | null - email?: string | null - full_name?: string | null - id?: string - updated_at?: string | null - website?: string | null - } - Relationships: [] - } - } + avatar_url?: string | null; + email?: string | null; + full_name?: string | null; + id?: string; + updated_at?: string | null; + website?: string | null; + }; + Relationships: []; + }; + }; Views: { - [_ in never]: never - } + user_tablos: { + Row: { + id: string; + owner_id: string; + name: string; + image: string | null; + color: string | null; + status: string; + position: number; + created_at: string | null; + deleted_at: string | null; + access_level: "owner" | "admin" | "member"; + is_admin: boolean; + granted_by: string | null; + access_granted_at: string | null; + }; + Relationships: []; + }; + }; Functions: { - [_ in never]: never - } + [_ in never]: never; + }; Enums: { - devis_status: "draft" | "sent" | "accepted" | "rejected" | "expired" - } + devis_status: "draft" | "sent" | "accepted" | "rejected" | "expired"; + }; CompositeTypes: { - [_ in never]: never - } - } -} + [_ in never]: never; + }; + }; +}; -type DefaultSchema = Database[Extract] +type DefaultSchema = Database[Extract]; export type Tables< DefaultSchemaTableNameOrOptions extends | keyof (DefaultSchema["Tables"] & DefaultSchema["Views"]) | { schema: keyof Database }, TableName extends DefaultSchemaTableNameOrOptions extends { - schema: keyof Database + schema: keyof Database; } ? keyof (Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & Database[DefaultSchemaTableNameOrOptions["schema"]]["Views"]) - : never = never, + : never = never > = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } ? (Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & Database[DefaultSchemaTableNameOrOptions["schema"]]["Views"])[TableName] extends { - Row: infer R + Row: infer R; } ? R : never : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema["Tables"] & - DefaultSchema["Views"]) - ? (DefaultSchema["Tables"] & - DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] extends { - Row: infer R - } - ? R - : never + DefaultSchema["Views"]) + ? (DefaultSchema["Tables"] & + DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] extends { + Row: infer R; + } + ? R : never + : never; export type TablesInsert< DefaultSchemaTableNameOrOptions extends | keyof DefaultSchema["Tables"] | { schema: keyof Database }, TableName extends DefaultSchemaTableNameOrOptions extends { - schema: keyof Database + schema: keyof Database; } ? keyof Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] - : never = never, + : never = never > = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } ? Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { - Insert: infer I + Insert: infer I; } ? I : never : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] - ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { - Insert: infer I - } - ? I - : never + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Insert: infer I; + } + ? I : never + : never; export type TablesUpdate< DefaultSchemaTableNameOrOptions extends | keyof DefaultSchema["Tables"] | { schema: keyof Database }, TableName extends DefaultSchemaTableNameOrOptions extends { - schema: keyof Database + schema: keyof Database; } ? keyof Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] - : never = never, + : never = never > = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } ? Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { - Update: infer U + Update: infer U; } ? U : never : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] - ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { - Update: infer U - } - ? U - : never + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Update: infer U; + } + ? U : never + : never; export type Enums< DefaultSchemaEnumNameOrOptions extends | keyof DefaultSchema["Enums"] | { schema: keyof Database }, EnumName extends DefaultSchemaEnumNameOrOptions extends { - schema: keyof Database + schema: keyof Database; } ? keyof Database[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"] - : never = never, + : never = never > = DefaultSchemaEnumNameOrOptions extends { schema: keyof Database } ? Database[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"][EnumName] : DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema["Enums"] - ? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions] - : never + ? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions] + : never; export type CompositeTypes< PublicCompositeTypeNameOrOptions extends | keyof DefaultSchema["CompositeTypes"] | { schema: keyof Database }, CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { - schema: keyof Database + schema: keyof Database; } ? keyof Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"] - : never = never, + : never = never > = PublicCompositeTypeNameOrOptions extends { schema: keyof Database } ? Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName] : PublicCompositeTypeNameOrOptions extends keyof DefaultSchema["CompositeTypes"] - ? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions] - : never + ? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions] + : never; export const Constants = { public: { @@ -217,4 +234,4 @@ export const Constants = { devis_status: ["draft", "sent", "accepted", "rejected", "expired"], }, }, -} as const +} as const;