建表,改表 辅助
drop table if exists h.ddl;
create table h.ddl(
id bigserial primary key ,
schemaName varchar not null,
tableName varchar not null,
columnName varchar not null,
columnType varchar not null,
position bigint not null,
checkRule varchar not null,
comment varchar not null,
defaultValue varchar not null,
primaryKey bool not null default false,
remark jsonb not null default '{}'
);
alter table h.ddl add unique (schemaname,tablename,columnName);
create or replace function h.ddl_beforeInsert() returns trigger language plpgsql as $$
begin
if new.position is null then
new.position = (select count(1) from h.ddl where (schemaname,tablename)=(new.schemaname,new.tablename));
end if;
return new;
end;
$$;
create trigger beforeInsert before insert on h.ddl for row execute procedure h.ddl_beforeInsert();
insert into h.ddl(id,schemaName,tablename,columnName,columnType,position,checkrule,comment,defaultvalue,primarykey) values
(-1,'public','test','id','bigint',0,'','', '',true)
,(-2,'public','test','c1','bigint',0,'','', '',false)
,(-3,'public','test','c2','bigint',0,'','', '',false);
create or replace function h.ddl_createTable(v_schemaName varchar,v_tableName varchar) returns void language plpgsql as $$
declare sql varchar;
begin
select string_agg(s,E'') into sql from (select format('create table %s.%s(', v_schemaName,v_tableName) union all
select * from (select format('%s %s not null %s constraint %s_%s_check check(%s),',columnname,columntype, case defaultvalue when '' then '' else 'default '||defaultvalue end, tablename,columnname, case checkrule when '' then 'true' else checkrule end) from h.ddl where (schemaname,tablename) =(v_schemaName,v_tableName) order by position) t union all
select format('primary key(%s)',(select string_agg(columnname,',') from h.ddl where (schemaname,tablename,primarykey) =(v_schemaName,v_tableName,true))) union all
select ');') t(s) ;
raise notice '%',sql;
execute sql;
end;
$$;
select h.ddl_createTable('public','test');
create or replace function h.ddl_renameColumn( v_schemaName varchar,v_tableName varchar,v_columnName varchar,v_newName varchar) returns jsonb language plpgsql as $$
declare
old_it h.ddl = (select ddl from h.ddl where (ddl.schemaName,ddl.tableName,ddl.columnName) = (v_schemaName,v_tableName,v_columnName)) ;
sql varchar;
begin
if old_it is null then return jsonb_build_object('code',1,'msg','该字段不存在'); end if;
update h.ddl set columnName =v_newName where id = old_it.id;
sql = format('alter table %s.%s rename column %s to %s;',v_schemaName,v_tableName,v_columnName,v_newName);
execute sql;
return jsonb_build_object('code',0);
end;
$$;
select h.ddl_renameColumn('public','test','pk','id');
create or replace function h.ddl_reCreateTable(v_schemaName varchar,v_tableName varchar) returns void language plpgsql as $$
declare sql varchar;
begin
sql = sql || (select string_agg(s,'') from (
select format('drop table if exists %s.%s__xxx;',v_schemaName,v_tableName) union all
select string_agg(s,E'') from (select format('create table %s.%s__xxx(', v_schemaName,v_tableName) union all
select string_agg(format('%s %s not null %s check(%s),',columnname,columntype,case defaultvalue when '' then '' else 'default '||defaultvalue end,case checkrule when '' then 'true' else checkrule end),'' order by position) from h.ddl where (schemaname,tablename) =(v_schemaName,v_tableName) union all
select format('primary key(%s)',(select string_agg(columnname,',') from h.ddl where (schemaname,tablename,primarykey) =(v_schemaName,v_tableName,true))) union all
select ');') t(s) union all
select format('insert into %s.%s__xxx select %s from %s.%s;',v_schemaName,v_tableName,(select string_agg(columnname||'::'||ddl.columntype,',' order by position) from h.ddl where (schemaname,tablename) = (v_schemaName,v_tableName)),v_schemaName,v_tableName) union all
select format('drop table if exists %s.%s;alter table %s.%s__xxx rename to %s;',v_schemaName,v_tableName,v_schemaName,v_tableName,v_tableName)
) t(s));
end;
$$;
create or replace function h.ddl_modifyColumn(jsonb) returns jsonb language plpgsql as $$
declare
it h.ddl = jsonb_populate_record(null::h.ddl,$1);
old_it h.ddl = (select ddl from h.ddl where (schemaName,tableName,columnName) = (it.schemaName,it.tableName,it.columnName)) ;
sql varchar = '';
begin
if old_it is null then return jsonb_build_object('code','1','msg','该字段不存在'); end if;
--
if it.columnType is not null then
update h.ddl set columnType =it.columnType where id = old_it.id;
sql = sql||format('alter table %s.%s alter column %s type %s using %s::%s;',it.schemaName,it.tableName,it.columnName,it.columnType,it.columnName,it.columnType);
end if;
--
if it.checkRule is not null then
update h.ddl set checkRule =it.checkRule where id = old_it.id;
-- 删除check
sql = sql|| format('alter table %s.%s drop constraint if exists %s_%s_check;',it.schemaName,it.tableName,it.tableName,it.columnName);
if it.checkRule != '' then
-- 新增check
sql = sql|| format('alter table %s.%s add check (%s) no inherit;',it.schemaName,it.tableName,it.checkRule);
end if;
end if;
--
if it.comment is not null then
update h.ddl set comment =it.comment where id = old_it.id;
sql = sql||format('comment on column %s.%s.%s is ''%s'';',it.schemaName,it.tableName,it.columnname,it.comment);
end if;
--
if it.defaultValue is not null then
update h.ddl set defaultValue = it.defaultValue where id = old_it.id;
sql = sql||format('alter table %s.%s alter column %s set default ''%s'';',it.schemaName,it.tableName,it.tableName,it.defaultValue);
end if;
--
if it.primarykey is not null then
update h.ddl set primaryKey = it.primaryKey where id = old_it.id;
-- 删除原主键
sql = sql||format('alter table %s.%s drop constraint if exists %s_pkey;',it.schemaName,it.tableName,it.tableName);
-- 创建新主键
if it.primarykey then
sql = sql||format('alter table %s.%s add constraint %s_pkey primary key (%s);',it.schemaName,it.tableName,it.tableName
,(select string_agg(columnname,',') from h.ddl where (schemaname,tablename,primarykey) =(it.schemaName,it.tableName,true)));
end if;
end if;
-- 修改了position, 会重新建表
if it.position is not null then
update h.ddl set position = it.position where id = old_it.id;
-- update h.ddl set position = it.position where (schemaName,tableName,columnName) = (it.schemaName,it.tableName,it.columnName);
perform h.ddl_reCreateTable(it.schemaName,it.tableName);
end if;
raise notice '%',sql;
execute sql;
return jsonb_build_object('code',0);
end;
$$;
select h.ddl_modifyColumn('{"schemaname":"public","tablename": "test","columnname": "id","primarykey": false}'::jsonb);
select h.ddl_modifyColumn('{"schemaname":"public","tablename": "test","columnname": "c1","columntype": "varchar","position": 2,"checkrule": "c1::int<10","primarykey": true}'::jsonb);
select h.ddl_modifyColumn('{"schemaname":"public","tablename": "test","columnname": "c1","columntype": "varchar","primarykey": true}'::jsonb);
select h.ddl_modifyColumn('{"schemaname":"public","tablename": "test","columnname": "c1","columntype": "varchar","comment": "注释"}'::jsonb);
select h.ddl_modifyColumn('{"schemaname":"public","tablename": "test","columnname": "id","position": 0,"comment": "主键"}'::jsonb);
select h.ddl_modifyColumn('{"schemaname":"public","tablename": "test","columnname": "c1","position": 1}'::jsonb);
select h.ddl_modifyColumn('{"schemaname":"public","tablename": "test","columnname": "c2","position": 2}'::jsonb);
select * from h.ddl;
drop table if exists public.player;
create table public.player(
id bigint not null,
avatar varchar not null, -- 头像
code varchar not null , -- 登录账号
salt varchar not null, -- 登录密码盐
level varchar not null, -- 级别
exp bigint not null, -- 经验值
coins bigint not null, -- 金币
password varchar not null, -- 登录密码
createAt bigint not null, -- 创建时间
updateAt bigint not null, -- 更新时间
-- 上边这些字段,管理员才能修改, 或由后台逻辑修改
nickname varchar not null check ( length(nickname) < 9 ), -- 昵称
birthday bigint not null, -- 生日, 可以给默认值 1901-01-01, 但若是某个业务单据的审批时间, 可以给个不可能出现的只, 比如 0001-01-01
bloodType varchar not null check ( bloodType in ('A','B','O','AB') ),
primary key (id)
);
insert into h.ddl(schemaName,tablename,columnName,columnType,comment,position,checkrule,defaultvalue,primarykey) values
('public','player','id','bigint','',default,'', '',true)
,('public','player','avatar','varchar','头像',default, '','',false)
,('public','player','code','varchar', '登录号',default,'','',false)
,('public','player','salt','varchar','密码盐',default,'', '',false)
,('public','player','level','bigint','等级',default,'', '',false)
,('public','player','exp','bigint','经验',default,'', '',false)
,('public','player','coins','bigint','金币',default,'', '',false)
,('public','player','password','varchar','',default,'', '',false)
,('public','player','createAt','bigint','',default,'', '',false)
,('public','player','updateAt','bigint','',default,'', '',false)
,('public','player','nickname','varchar','',default,'', '',false)
,('public','player','birthday','bigint','',default,'', '',false)
,('public','player','bloodType','varchar','',default,'', '',false)
;
delete from h.ddl where true;;
select * from h.ddl order by id ;
drop table if exists public.player;
select h.ddl_createTable('public','player');
select * from public.player;
create table public.player(avatar varchar not null constraint player_avatar_check check(true),birthday bigint not null constraint player_birthday_check check(true),bloodType varchar not null constraint player_bloodType_check check(true),code varchar not null default 登录号 constraint player_code_check check(true),coins bigint not null constraint player_coins_check check(true),createAt bigint not null constraint player_createAt_check check(true),exp bigint not null constraint player_exp_check check(经验),id bigint not null constraint player_id_check check(true),level bigint not null constraint player_level_check check(等级),nickname varchar not null constraint player_nickname_check check(true),password varchar not null constraint player_password_check check(true),salt varchar not null constraint player_salt_check check(密码盐),updateAt bigint not null constraint player_updateAt_check check(true),primary key(id));
物理删除备份schema
-- 物理删除备份schema
create schema DeletedBackup;
drop table if exists DeletedBackup.FieldPermission;
create table DeletedBackup.FieldPermission(
id long, uri string, tableName string ,operation long
,roleIds long[] -- 适用的角色
,fields string[] -- 允许的字段
,createAt long,createOr long,updateAt long,modifier long
,oCreateAt long,oCreator -- 操作人, 操作时间
);
角色-字段操作权限
drop table if exists DeletedBackup.FieldPermission;
create table DeletedBackup.FieldPermission(
id long, uri string, tableName string ,operation long
,roleIds long[] -- 适用的角色
,fields string[] -- 允许的字段
,createAt long,createOr long,updateAt long,modifier long
,oCreateAt long,oCreator long -- 操作人, 操作时间
);
drop table if exists public.SysRoleAccount;
create table public.SysRoleAccount(
id long, roleId long,accountId long, usable long
,createAt long,createOr long,updateAt long,modifier long
);
-- 某个用户, 在某个接口内, 可传参修改哪些字段
select unnest(fields) from FieldPermission where (uri,tableName,operation) = ('','',0) and (select unnest(roleIds) intersect select roleId from SysRoleAccount where usable = 0 and accountId = ? limit 1)>0;
-- 一般来说, 也用不到这么精确控制, 需要禁用时走前端, 而不是接口处理, 不过可以通过配置这里, 反过来统一禁用前端控件
select fields @> array['']::string[] from FieldPermission where (uri,tableName,operation) = ('','',0) and (select unnest(roleIds) intersect select roleId from SysRoleAccount where usable = 0 and accountId = ? limit 1)>0;
-- 做交集运算时, limit 1 将针对两边, 而不是后部分
select * from (values(1),(2)) t intersect select * from (values(3),(2)) t2 limit 1;