Created
May 10, 2012 19:44
-
-
Save troyk/2655391 to your computer and use it in GitHub Desktop.
Postgres is the snizzle
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class CreateAccounts < ActiveRecord::Migration | |
| def up | |
| #return unless connection.schema_search_path == 'public' | |
| #-- create a dummy schema so migrations will run | |
| execute "CREATE SCHEMA crm0;" | |
| #-- citext is cool (I think) | |
| execute "CREATE EXTENSION IF NOT EXISTS citext;" | |
| #-- public/shared types | |
| execute "CREATE TYPE public.contacts_type AS ENUM ('Person', 'Organization');" | |
| execute "CREATE TYPE public.contacts_infos_type AS ENUM ('Contact::Address', 'Contact::Phone', 'Contact::Email', 'Contact::Website');" | |
| #-- public schema | |
| execute <<-SQL | |
| CREATE TABLE IF NOT EXISTS public.accounts ( | |
| id serial PRIMARY KEY, | |
| created_at timestamp with time zone NOT NULL DEFAULT NOW(), | |
| name citext NOT NULL | |
| ); | |
| SQL | |
| #-- trigger function to clone/delete a schema for accounts table | |
| execute <<-SQL | |
| CREATE OR REPLACE FUNCTION public.accounts_fntrig_schema() RETURNS TRIGGER AS $BODY$ | |
| DECLARE | |
| crm0_table_name text; | |
| act_table_name text; | |
| BEGIN | |
| IF TG_OP = 'INSERT' THEN | |
| EXECUTE 'CREATE SCHEMA crm' || NEW.id ; | |
| FOR crm0_table_name IN | |
| SELECT table_name::text FROM information_schema.TABLES WHERE table_schema = 'crm0' | |
| LOOP | |
| act_table_name := 'crm' || NEW.id || '.' || crm0_table_name; | |
| EXECUTE 'CREATE TABLE ' || act_table_name || ' (LIKE ' || 'crm0' || '.' || crm0_table_name || ' INCLUDING ALL)'; | |
| END LOOP; | |
| --EXECUTE 'INSERT INTO crm' || NEW.id || '.schema_migrations (SELECT * FROM crm0.schema_migrations)'; | |
| ELSIF TG_OP = 'DELETE' THEN | |
| EXECUTE 'DROP SCHEMA crm' || OLD.id || ' CASCADE'; | |
| ELSE | |
| RAISE EXCEPTION 'TG_OP % not supported in this trigger bro', TG_OP; | |
| END IF; | |
| RETURN NULL; | |
| END; | |
| $BODY$ LANGUAGE plpgsql; | |
| SQL | |
| execute "CREATE TRIGGER accounts_trig_schema AFTER INSERT OR DELETE ON public.accounts FOR EACH ROW EXECUTE PROCEDURE public.accounts_fntrig_schema()" | |
| end | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # check out this psql console output showing how transactional ddl, triggers and bodacious | |
| # CREATE TABLE LIKE make postgres rock for multi-tenant! | |
| blit5=# \dn | |
| List of schemas | |
| Name | Owner | |
| --------+------- | |
| crm0 | troy | |
| public | troy | |
| (2 rows) | |
| blit5=# \d accounts | |
| Table "public.accounts" | |
| Column | Type | Modifiers | |
| ------------+--------------------------+------------------------------------------------------- | |
| id | integer | not null default nextval('accounts_id_seq'::regclass) | |
| created_at | timestamp with time zone | not null default now() | |
| name | citext | not null | |
| Indexes: | |
| "accounts_pkey" PRIMARY KEY, btree (id) | |
| Referenced by: | |
| TABLE "account_users" CONSTRAINT "account_users_account_id_fkey" FOREIGN KEY (account_id) REFERENCES accounts(id) ON UPDATE CASCADE | |
| Triggers: | |
| accounts_trig_schema AFTER INSERT OR DELETE ON accounts FOR EACH ROW EXECUTE PROCEDURE accounts_fntrig_schema() | |
| blit5=# insert into accounts(name) values('Blit rocks!'); | |
| NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "contact_infos_pkey" for table "contact_infos" | |
| CONTEXT: SQL statement "CREATE TABLE crm1.contact_infos (LIKE crm0.contact_infos INCLUDING ALL)" | |
| PL/pgSQL function "accounts_fntrig_schema" line 13 at EXECUTE statement | |
| NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "contacts_pkey" for table "contacts" | |
| CONTEXT: SQL statement "CREATE TABLE crm1.contacts (LIKE crm0.contacts INCLUDING ALL)" | |
| PL/pgSQL function "accounts_fntrig_schema" line 13 at EXECUTE statement | |
| ERROR: control reached end of trigger procedure without RETURN | |
| CONTEXT: PL/pgSQL function "accounts_fntrig_schema" | |
| blit5=# select * from accounts; | |
| id | created_at | name | |
| ----+------------+------ | |
| (0 rows) | |
| blit5=# drop FUNCTION public.accounts_fntrig_schema() cascade; | |
| NOTICE: drop cascades to trigger accounts_trig_schema on table accounts | |
| DROP FUNCTION | |
| blit5=# \d accounts | |
| Table "public.accounts" | |
| Column | Type | Modifiers | |
| ------------+--------------------------+------------------------------------------------------- | |
| id | integer | not null default nextval('accounts_id_seq'::regclass) | |
| created_at | timestamp with time zone | not null default now() | |
| name | citext | not null | |
| Indexes: | |
| "accounts_pkey" PRIMARY KEY, btree (id) | |
| Referenced by: | |
| TABLE "account_users" CONSTRAINT "account_users_account_id_fkey" FOREIGN KEY (account_id) REFERENCES accounts(id) ON UPDATE CASCADE | |
| blit5=# CREATE OR REPLACE FUNCTION public.accounts_fntrig_schema() RETURNS TRIGGER AS $BODY$ | |
| blit5$# DECLARE | |
| blit5$# crm0_table_name text; | |
| blit5$# act_table_name text; | |
| blit5$# BEGIN | |
| blit5$# IF TG_OP = 'INSERT' THEN | |
| blit5$# EXECUTE 'CREATE SCHEMA crm' || NEW.id ; | |
| blit5$# | |
| blit5$# FOR crm0_table_name IN | |
| blit5$# SELECT table_name::text FROM information_schema.TABLES WHERE table_schema = 'crm0' | |
| blit5$# LOOP | |
| blit5$# act_table_name := 'crm' || NEW.id || '.' || crm0_table_name; | |
| blit5$# EXECUTE 'CREATE TABLE ' || act_table_name || ' (LIKE ' || 'crm0' || '.' || crm0_table_name || ' INCLUDING ALL)'; | |
| blit5$# END LOOP; | |
| blit5$# --EXECUTE 'INSERT INTO crm' || NEW.id || '.schema_migrations (SELECT * FROM crm0.schema_migrations)'; | |
| blit5$# ELSIF TG_OP = 'DELETE' THEN | |
| blit5$# EXECUTE 'DROP SCHEMA crm' || OLD.id || ' CASCADE'; | |
| blit5$# ELSE | |
| blit5$# RAISE EXCEPTION 'TG_OP % not supported in this trigger bro', TG_OP; | |
| blit5$# END IF; | |
| blit5$# RETURN NULL; | |
| blit5$# END; | |
| blit5$# $BODY$ LANGUAGE plpgsql; | |
| CREATE FUNCTION | |
| blit5=# CREATE TRIGGER accounts_trig_schema AFTER INSERT OR DELETE ON public.accounts FOR EACH ROW EXECUTE PROCEDURE public.accounts_fntrig_schema(); | |
| CREATE TRIGGER | |
| blit5=# \d accounts | |
| Table "public.accounts" | |
| Column | Type | Modifiers | |
| ------------+--------------------------+------------------------------------------------------- | |
| id | integer | not null default nextval('accounts_id_seq'::regclass) | |
| created_at | timestamp with time zone | not null default now() | |
| name | citext | not null | |
| Indexes: | |
| "accounts_pkey" PRIMARY KEY, btree (id) | |
| Referenced by: | |
| TABLE "account_users" CONSTRAINT "account_users_account_id_fkey" FOREIGN KEY (account_id) REFERENCES accounts(id) ON UPDATE CASCADE | |
| Triggers: | |
| accounts_trig_schema AFTER INSERT OR DELETE ON accounts FOR EACH ROW EXECUTE PROCEDURE accounts_fntrig_schema() | |
| blit5=# insert into accounts(name) values('Blit rocks!');NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "contact_infos_pkey" for table "contact_infos"CONTEXT: SQL statement "CREATE TABLE crm2.contact_infos (LIKE crm0.contact_infos INCLUDING ALL)"PL/pgSQL function "accounts_fntrig_schema" line 13 at EXECUTE statementNOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "contacts_pkey" for table "contacts"CONTEXT: SQL statement "CREATE TABLE crm2.contacts (LIKE crm0.contacts INCLUDING ALL)"PL/pgSQL function "accounts_fntrig_schema" line 13 at EXECUTE statementINSERT 0 1blit5=# select * from accounts; id | created_at | name ----+-------------------------------+------------- 2 | 2012-05-10 12:34:11.519005-07 | Blit rocks!(1 row)blit5=# \dn List of schemas Name | Owner --------+------- crm0 | troy crm2 | troy public | troy(3 rows)blit5=# \dn crm2List of schemas Name | Owner ------+------- crm2 | troy(1 row)blit5=# \dn+ crm2 List of schemas Name | Owner | Access privileges | Description ------+-------+-------------------+------------- crm2 | troy | | (1 row) | |
| blit5=# SELECT table_name::text FROM information_schema.TABLES WHERE table_schema = 'crm2'; | |
| table_name | |
| --------------- | |
| contact_infos | |
| contacts | |
| (2 rows) | |
| blit5=# \d crm2.contacts; | |
| Table "crm2.contacts" | |
| Column | Type | Modifiers | |
| -------------------------+--------------------------+------------------------------------------------------------ | |
| id | integer | not null default nextval('crm0.contacts_id_seq'::regclass) | |
| type | contacts_type | not null | |
| created_at | timestamp with time zone | not null default now() | |
| updated_at | timestamp with time zone | not null default now() | |
| todo_at | timestamp with time zone | | |
| created_by_id | citext | not null | |
| organization_id | integer | | |
| organization_num_people | integer | | |
| name | citext | | |
| first_name | citext | | |
| last_name | citext | | |
| title | citext | | |
| background | citext | | |
| Indexes: | |
| "contacts_pkey" PRIMARY KEY, btree (id) | |
| "contacts_created_by_id_idx" btree (created_by_id) | |
| "contacts_organization_id_idx" btree (organization_id) | |
| blit5=# \d crm2.contact_infos; | |
| Table "crm2.contact_infos" | |
| Column | Type | Modifiers | |
| ------------+---------------------+----------------------------------------------------------------- | |
| id | integer | not null default nextval('crm0.contact_infos_id_seq'::regclass) | |
| type | contacts_infos_type | not null | |
| contact_id | integer | not null | |
| label | citext | | |
| address | citext | | |
| city | citext | | |
| state | citext | | |
| zip | citext | | |
| Indexes: | |
| "contact_infos_pkey" PRIMARY KEY, btree (id) | |
| "contact_infos_contact_id_idx" btree (contact_id) | |
| blit5=# |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment