-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: auto crud #51
base: master
Are you sure you want to change the base?
WIP: auto crud #51
Changes from 4 commits
b5e31bd
b927bc1
c46a484
ebf681b
c506e2d
293eb09
75e3c49
cba32f2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
module.exports = (binding) => { | ||
let columns = binding.fields.filter(f => !f.identity).map(f => `[${f.column}]`).join(', '); | ||
return ` | ||
CREATE PROCEDURE ${binding.spName} | ||
@data ${binding.tt} READONLY | ||
AS | ||
SET NOCOUNT ON | ||
DECLARE @result ${binding.tt} | ||
BEGIN TRY | ||
INSERT INTO ${binding.name} (${columns}) | ||
OUTPUT INSERTED.* INTO @result | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No praticular reason. Just thought that storing the data in a table type would be easier to return all the data as a named resultset at the end. |
||
SELECT ${columns} | ||
FROM @data | ||
|
||
SELECT 'data' AS resultSetName | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we discuss if 'data' is good as name? If we call multiple procedures as part of a bigger one, it is better each to return different name for the resultset. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure. Instead of 'data' it can be the table name. e.g. 'customer.customer', 'customer.organization', etc. |
||
SELECT * from @result | ||
END TRY | ||
BEGIN CATCH | ||
IF @@TRANCOUNT != 0 | ||
ROLLBACK TRANSACTION | ||
DECLARE | ||
@errmsg NVARCHAR(2048), | ||
@severity TINYINT, | ||
@state TINYINT, | ||
@errno INT, | ||
@proc sysname, | ||
@lineno INT | ||
SELECT | ||
@errmsg = error_message(), | ||
@severity = error_severity(), | ||
@state = error_state(), | ||
@errno = error_number(), | ||
@proc = error_procedure(), | ||
@lineno = error_line() | ||
IF @errmsg NOT LIKE '***%' | ||
BEGIN | ||
SELECT @errmsg = '*** ' + COALESCE(QUOTENAME(@proc), '<dynamic SQL>') + | ||
', Line ' + LTRIM(STR(@lineno)) + '. Errno ' + | ||
LTRIM(STR(@errno)) + ': ' + @errmsg | ||
END | ||
RAISERROR('%s', @severity, @state, @errmsg) | ||
RETURN 55555 | ||
END CATCH | ||
`; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module.exports = () => { | ||
return ``; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
const crud = { | ||
create: require('./create'), | ||
read: require('./read'), | ||
update: require('./update'), | ||
delete: require('./delete') | ||
}; | ||
|
||
module.exports = { | ||
actions: Object.keys(crud), | ||
generate: (binding, action) => { | ||
let name; | ||
let suffix; | ||
if (binding.name.match(/]$/)) { | ||
name = binding.name.slice(0, -1); | ||
suffix = ']'; | ||
} else { | ||
name = binding.name; | ||
suffix = ''; | ||
} | ||
binding.spName = `${name}.${action}${suffix}`; | ||
binding.tt = `${name}TT${suffix}`; | ||
binding.ttu = `${name}TTU${suffix}`; | ||
return crud[action](binding); | ||
} | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module.exports = () => { | ||
return ``; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module.exports = () => { | ||
return ``; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
module.exports = function(statement) { | ||
if (!statement.params) { | ||
return; | ||
} | ||
var sql = ' DECLARE @callParams XML = ( SELECT '; | ||
statement.params.map(function(param) { | ||
if (param.def.type === 'table') { | ||
sql += `(SELECT * from @${param.name} rows FOR XML AUTO, TYPE) [${param.name}], `; | ||
} else { | ||
sql += `@${param.name} [${param.name}], `; | ||
} | ||
}); | ||
sql = sql.replace(/,\s$/, ' '); | ||
sql += 'FOR XML RAW(\'params\'),TYPE) EXEC core.auditCall @procid = @@PROCID, @params=@callParams'; | ||
return sql; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
module.exports = function(statement) { | ||
if (!statement.params) { | ||
return; | ||
} | ||
var sql = 'DECLARE @callParams XML = ( SELECT '; | ||
statement.params.map(function(param) { | ||
if (param.def.type === 'table') { | ||
sql += `(SELECT * from @${param.name} rows FOR XML AUTO, TYPE) [${param.name}], `; | ||
} else { | ||
sql += `@${param.name} [${param.name}], `; | ||
} | ||
}); | ||
sql = sql.replace(/,\s$/, ' '); | ||
sql += 'FOR XML RAW(\'params\'),TYPE)'; | ||
return sql; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
module.exports = function(name, user) { | ||
return ` | ||
IF NOT EXISTS (SELECT name FROM master.dbo.sysdatabases WHERE name = '${name}') | ||
BEGIN | ||
CREATE DATABASE [${name}] | ||
ALTER DATABASE [${name}] SET READ_COMMITTED_SNAPSHOT ON | ||
ALTER DATABASE [${name}] SET AUTO_SHRINK OFF | ||
END`; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
module.exports = function(name, user, password) { | ||
return ` | ||
IF NOT EXISTS (SELECT name FROM master.sys.server_principals WHERE name = '${user}') | ||
BEGIN | ||
CREATE LOGIN [${user}] WITH PASSWORD = N'${password}', CHECK_POLICY = OFF | ||
END | ||
USE [${name}] | ||
IF NOT EXISTS (SELECT name FROM sys.database_principals WHERE name = '${user}') | ||
BEGIN | ||
CREATE USER [${user}] FOR LOGIN [${user}] | ||
END | ||
IF (is_rolemember('db_owner', '${user}') IS NULL OR is_rolemember('db_owner', '${user}') = 0) | ||
BEGIN | ||
EXEC sp_addrolemember 'db_owner', '${user}' | ||
END | ||
IF NOT EXISTS (SELECT 1 FROM sys.server_principals AS pr | ||
INNER JOIN sys.server_permissions AS pe ON pe.grantee_principal_id = pr.principal_id | ||
WHERE permission_name = N'VIEW SERVER STATE' AND state = N'G' AND pr.name = N'${user}') | ||
BEGIN | ||
USE [master] | ||
GRANT VIEW SERVER STATE to [${user}] | ||
END | ||
`; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
module.exports = function(name) { | ||
return ` | ||
USE [${name}] | ||
IF OBJECT_ID(N'dbo.fn_diagramobjects') IS NULL and IS_MEMBER('db_owner') = 1 | ||
DROP FUNCTION dbo.fn_diagramobjects | ||
IF OBJECT_ID(N'dbo.sp_dropdiagram') IS NULL and IS_MEMBER('db_owner') = 1 | ||
DROP PROCEDURE dbo.sp_dropdiagram | ||
IF OBJECT_ID(N'dbo.sp_alterdiagram') IS NULL and IS_MEMBER('db_owner') = 1 | ||
DROP PROCEDURE dbo.sp_alterdiagram | ||
IF OBJECT_ID(N'dbo.sp_renamediagram') IS NULL and IS_MEMBER('db_owner') = 1 | ||
DROP PROCEDURE dbo.sp_renamediagram | ||
IF OBJECT_ID(N'dbo.sp_creatediagram') IS NULL and IS_MEMBER('db_owner') = 1 | ||
DROP PROCEDURE dbo.sp_creatediagram | ||
IF OBJECT_ID(N'dbo.sp_helpdiagramdefinition') IS NULL and IS_MEMBER('db_owner') = 1 | ||
DROP PROCEDURE dbo.sp_helpdiagramdefinition | ||
IF OBJECT_ID(N'dbo.sp_helpdiagrams') IS NULL and IS_MEMBER('db_owner') = 1 | ||
DROP PROCEDURE dbo.sp_helpdiagrams | ||
IF OBJECT_ID(N'dbo.sysdiagrams') IS NOT NULL and IS_MEMBER('db_owner') = 1 | ||
DROP TABLE dbo.sysdiagrams | ||
IF OBJECT_ID(N'dbo.sp_upgraddiagrams') IS NULL and IS_MEMBER('db_owner') = 1 | ||
DROP PROCEDURE dbo.sp_upgraddiagrams`; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module.exports = function() { | ||
return `IF OBJECT_ID('dbo.utSchemaHash') IS NOT NULL DROP FUNCTION dbo.utSchemaHash`; | ||
}; |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module.exports = function() { | ||
return `IF OBJECT_ID('dbo.utSchemaHash') IS NOT NULL SELECT dbo.utSchemaHash() hash`; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
module.exports = { | ||
auditLog: require('./auditLog'), | ||
callParams: require('./callParams'), | ||
createDatabase: require('./createDatabase'), | ||
createUser: require('./createUser'), | ||
disableDatabaseDiagrams: require('./disableDatabaseDiagrams'), | ||
dropHash: require('./dropHash'), | ||
enableDatabaseDiagrams: require('./enableDatabaseDiagrams'), | ||
getHash: require('./getHash'), | ||
loadSchema: require('./loadSchema'), | ||
refreshView: require('./refreshView'), | ||
setHash: require('./setHash') | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
module.exports = function(partial) { | ||
return ` | ||
SELECT | ||
o.create_date, | ||
c.id, | ||
c.colid, | ||
RTRIM(o.[type]) [type], | ||
SCHEMA_NAME(o.schema_id) [namespace], | ||
o.Name AS [name], | ||
SCHEMA_NAME(o.schema_id) + '.' + o.Name AS [full], | ||
CASE o.[type] | ||
WHEN 'SN' THEN 'DROP SYNONYM [' + SCHEMA_NAME(o.schema_id) + '].[' + o.Name + | ||
'] CREATE SYNONYM [' + SCHEMA_NAME(o.schema_id) + '].[' + o.Name + '] FOR ' + s.base_object_name | ||
ELSE ${partial ? `LEFT(c.text, CASE CHARINDEX(CHAR(10)+'AS'+CHAR(13), c.text) WHEN 0 THEN 2500 ELSE CHARINDEX(CHAR(10)+'AS'+CHAR(13), c.text) + 10 END)` : 'c.text'} | ||
END AS [source] | ||
FROM | ||
sys.objects o | ||
LEFT JOIN | ||
dbo.syscomments c on o.object_id = c.id | ||
LEFT JOIN | ||
sys.synonyms s on s.object_id = o.object_id | ||
WHERE | ||
o.type IN (${partial ? `'P'` : `'V', 'P', 'FN','F','IF','SN','TF','TR','U'`}) AND | ||
user_name(objectproperty(o.object_id, 'OwnerId')) in (USER_NAME(),'dbo') AND | ||
objectproperty(o.object_id, 'IsMSShipped') = 0 AND | ||
SCHEMA_NAME(o.schema_id) != 'dbo' | ||
${partial ? 'AND ISNULL(c.colid, 1)=1' : ''} | ||
UNION ALL | ||
SELECT 0,0,0,'S',name,NULL,NULL,NULL FROM sys.schemas WHERE principal_id = USER_ID() | ||
UNION ALL | ||
SELECT | ||
0,0,0,'T',SCHEMA_NAME(t.schema_id)+'.'+t.name,NULL,NULL,NULL | ||
FROM | ||
sys.types t | ||
JOIN | ||
sys.schemas s ON s.principal_id = USER_ID() AND s.schema_id=t.schema_id | ||
WHERE | ||
t.is_user_defined=1 | ||
ORDER BY | ||
1, 2, 3 | ||
SELECT | ||
SCHEMA_NAME(types.schema_id) + '.' + types.name name, | ||
c.name [column], | ||
st.name type, | ||
CASE | ||
WHEN st.name in ('decimal','numeric') then CAST(c.[precision] AS VARCHAR) | ||
WHEN st.name in ('datetime2','time','datetimeoffset') then CAST(c.[scale] AS VARCHAR) | ||
WHEN st.name in ('varchar','varbinary','char','binary') AND c.max_length>=0 THEN CAST(c.max_length as VARCHAR) | ||
WHEN st.name in ('nvarchar','nchar') AND c.max_length>=0 THEN CAST(c.max_length/2 as VARCHAR) | ||
WHEN st.name in ('varchar','varbinary','char','binary','nvarchar','nchar') AND c.max_length<0 THEN 'max' | ||
END [length], | ||
CASE | ||
WHEN st.name in ('decimal','numeric') then c.scale | ||
END scale, | ||
object_definition(c.default_object_id) [default] | ||
FROM | ||
sys.table_types types | ||
JOIN | ||
sys.columns c ON types.type_table_object_id = c.object_id | ||
JOIN | ||
sys.systypes AS st ON st.xtype = c.system_type_id | ||
WHERE | ||
types.is_user_defined = 1 AND st.name <> 'sysname' | ||
ORDER BY | ||
1,c.column_id | ||
SELECT | ||
1 sort, | ||
s.name + '.' + o.name [name], | ||
'IF (OBJECT_ID(''[' + s.name + '].[' + o.name + ']'') IS NOT NULL) DROP ' + CASE o.type WHEN 'FN' THEN 'FUNCTION' ELSE 'PROCEDURE' END + ' [' + s.name + '].[' + o.name + ']' [drop], | ||
p.name [param], | ||
SCHEMA_NAME(t.schema_id) + '.' + t.name [type] | ||
FROM | ||
sys.schemas s | ||
JOIN | ||
sys.objects o ON o.schema_id = s.schema_id | ||
JOIN | ||
sys.parameters p ON p.object_id = o.object_id | ||
JOIN | ||
sys.types t ON p.user_type_id = t.user_type_id AND t.is_user_defined=1 | ||
WHERE | ||
user_name(objectproperty(o.object_id, 'OwnerId')) in (USER_NAME(),'dbo') | ||
UNION | ||
SELECT | ||
2, | ||
s.name + '.' + t.name [name], | ||
'DROP TYPE [' + s.name + '].[' + t.name + ']' [drop], | ||
NULL [param], | ||
SCHEMA_NAME(t.schema_id) + '.' + t.name [type] | ||
FROM | ||
sys.schemas s | ||
JOIN | ||
sys.types t ON t.schema_id=s.schema_id and t.is_user_defined=1 | ||
WHERE | ||
user_name(s.principal_id) in (USER_NAME(),'dbo') | ||
ORDER BY 1`; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
module.exports = function(drop) { | ||
return ` | ||
SET NOCOUNT ON; | ||
DECLARE @ViewName VARCHAR(255); | ||
DECLARE @error_table TABLE | ||
( | ||
view_name VARCHAR(255) , | ||
error_msg VARCHAR(MAX) | ||
); | ||
DECLARE view_cursor CURSOR FAST_FORWARD | ||
FOR | ||
--- Get all the user defined views with no schema binding on them | ||
SELECT DISTINCT | ||
'[' + ss.name + '].[' + av.name +']' AS ViewName | ||
FROM sys.all_views av | ||
JOIN sys.schemas ss ON av.schema_id = ss.schema_id | ||
WHERE OBJECTPROPERTY(av.[object_id], 'IsSchemaBound') <> 1 | ||
AND av.Is_Ms_Shipped = 0 | ||
OPEN view_cursor | ||
FETCH NEXT FROM view_cursor | ||
INTO @ViewName | ||
WHILE @@FETCH_STATUS = 0 | ||
BEGIN | ||
BEGIN TRY | ||
-- Refresh the view | ||
EXEC sp_refreshview @ViewName; | ||
-- RAISERROR('%s', 10, 1, @ViewName) WITH NOWAIT; | ||
END TRY | ||
BEGIN CATCH | ||
IF @@trancount > 0 ROLLBACK TRANSACTION | ||
--- Insert all the errors | ||
IF (1=${drop ? 1 : 0}) | ||
BEGIN | ||
EXEC ('DROP VIEW ' + @ViewName) | ||
END ELSE | ||
BEGIN | ||
INSERT INTO | ||
@error_table(view_name, error_msg) | ||
SELECT @ViewName, ERROR_MESSAGE(); | ||
END | ||
END CATCH | ||
FETCH NEXT FROM view_cursor INTO @ViewName; | ||
END | ||
--- Check if there was an error | ||
IF EXISTS (SELECT TOP 1 1 FROM @error_table) | ||
BEGIN | ||
SELECT view_name , | ||
error_msg | ||
FROM @error_table; | ||
END | ||
CLOSE view_cursor | ||
DEALLOCATE view_cursor | ||
IF OBJECT_ID('dbo.utSchemaHash') IS NOT NULL SELECT dbo.utSchemaHash() hash | ||
SET NOCOUNT OFF;`; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module.exports = function(hash) { | ||
return `CREATE FUNCTION dbo.utSchemaHash() RETURNS VARCHAR(64) AS BEGIN RETURN '${hash}' END`; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also have a generic logic for checking for already existing records and raising standard errors?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I just wrote some generic SQL code which I didn't mean to be final ... just to test the concept.
We can change the bodies and the names of the procedures however we like. My main idea was to align with you whether the changes in index.js are fine. Maybe @mlessevsg can help with the SQL.