Replace raw-JSON text inputs with rich UI: script parameter/return types use a JSON Schema builder (SchemaBuilder + JsonSchemaShapeParser, with a migration to convert existing definitions); alarm trigger config uses a type-aware editor with a flattened attribute picker (AlarmTriggerEditor). AlarmActor gains optional direction (rising/falling/either) on RateOfChange triggers.
197 lines
7.0 KiB
C#
197 lines
7.0 KiB
C#
using Microsoft.EntityFrameworkCore.Migrations;
|
|
|
|
#nullable disable
|
|
|
|
namespace ScadaLink.ConfigurationDatabase.Migrations
|
|
{
|
|
/// <inheritdoc />
|
|
public partial class MigrateParametersToJsonSchema : Migration
|
|
{
|
|
/// <inheritdoc />
|
|
protected override void Up(MigrationBuilder migrationBuilder)
|
|
{
|
|
// Convert legacy flat-shape parameter / return JSON in TemplateScripts,
|
|
// SharedScripts, and ApiMethods to JSON Schema.
|
|
//
|
|
// Parameters [{name,type,required,itemType?}]
|
|
// → {"type":"object","properties":{<name>:{"type":<jsType>}},"required":[...]}
|
|
//
|
|
// Return {type,itemType?}
|
|
// → {"type":<jsType>} or {"type":"array","items":{"type":<inner>}}
|
|
//
|
|
// Idempotent: only rows whose value starts with '[' (parameters) or that
|
|
// contain the legacy 'List' sentinel (return) are touched. Already-converted
|
|
// rows are skipped.
|
|
|
|
migrationBuilder.Sql(@"
|
|
IF OBJECT_ID('dbo.fn_LegacyTypeToJsonSchemaType', 'FN') IS NOT NULL
|
|
DROP FUNCTION dbo.fn_LegacyTypeToJsonSchemaType;
|
|
");
|
|
|
|
migrationBuilder.Sql(@"
|
|
CREATE FUNCTION dbo.fn_LegacyTypeToJsonSchemaType(@legacy NVARCHAR(50))
|
|
RETURNS NVARCHAR(50)
|
|
AS
|
|
BEGIN
|
|
RETURN
|
|
CASE LOWER(ISNULL(@legacy, 'string'))
|
|
WHEN 'boolean' THEN 'boolean'
|
|
WHEN 'bool' THEN 'boolean'
|
|
WHEN 'integer' THEN 'integer'
|
|
WHEN 'int' THEN 'integer'
|
|
WHEN 'int32' THEN 'integer'
|
|
WHEN 'int64' THEN 'integer'
|
|
WHEN 'float' THEN 'number'
|
|
WHEN 'double' THEN 'number'
|
|
WHEN 'decimal' THEN 'number'
|
|
WHEN 'number' THEN 'number'
|
|
WHEN 'string' THEN 'string'
|
|
WHEN 'datetime' THEN 'string'
|
|
WHEN 'object' THEN 'object'
|
|
WHEN 'list' THEN 'array'
|
|
WHEN 'array' THEN 'array'
|
|
ELSE 'string'
|
|
END;
|
|
END;
|
|
");
|
|
|
|
migrationBuilder.Sql(@"
|
|
IF OBJECT_ID('dbo.fn_LegacyParametersToJsonSchema', 'FN') IS NOT NULL
|
|
DROP FUNCTION dbo.fn_LegacyParametersToJsonSchema;
|
|
");
|
|
|
|
migrationBuilder.Sql(@"
|
|
CREATE FUNCTION dbo.fn_LegacyParametersToJsonSchema(@legacy NVARCHAR(MAX))
|
|
RETURNS NVARCHAR(MAX)
|
|
AS
|
|
BEGIN
|
|
IF @legacy IS NULL OR LTRIM(@legacy) = '' RETURN NULL;
|
|
IF LEFT(LTRIM(@legacy), 1) <> '[' RETURN @legacy; -- already schema-shaped
|
|
|
|
DECLARE @props NVARCHAR(MAX) = (
|
|
SELECT STRING_AGG(
|
|
CONCAT(
|
|
'""',
|
|
STRING_ESCAPE(JSON_VALUE(p.value, '$.name'), 'json'),
|
|
'"":',
|
|
CASE
|
|
WHEN LOWER(ISNULL(JSON_VALUE(p.value, '$.type'), 'string')) IN ('list', 'array')
|
|
THEN CONCAT(
|
|
'{""type"":""array"",""items"":{""type"":""',
|
|
dbo.fn_LegacyTypeToJsonSchemaType(JSON_VALUE(p.value, '$.itemType')),
|
|
'""}}')
|
|
ELSE CONCAT(
|
|
'{""type"":""',
|
|
dbo.fn_LegacyTypeToJsonSchemaType(JSON_VALUE(p.value, '$.type')),
|
|
'""}')
|
|
END),
|
|
',')
|
|
WITHIN GROUP (ORDER BY p.[key])
|
|
FROM OPENJSON(@legacy) p
|
|
WHERE JSON_VALUE(p.value, '$.name') IS NOT NULL
|
|
AND JSON_VALUE(p.value, '$.name') <> ''
|
|
);
|
|
|
|
DECLARE @required NVARCHAR(MAX) = (
|
|
SELECT STRING_AGG(
|
|
CONCAT('""', STRING_ESCAPE(JSON_VALUE(p.value, '$.name'), 'json'), '""'),
|
|
',')
|
|
WITHIN GROUP (ORDER BY p.[key])
|
|
FROM OPENJSON(@legacy) p
|
|
WHERE JSON_VALUE(p.value, '$.name') IS NOT NULL
|
|
AND JSON_VALUE(p.value, '$.name') <> ''
|
|
AND LOWER(ISNULL(JSON_VALUE(p.value, '$.required'), 'true')) <> 'false'
|
|
);
|
|
|
|
RETURN
|
|
'{""type"":""object"",""properties"":{' + ISNULL(@props, '') + '}'
|
|
+ CASE WHEN @required IS NULL OR @required = '' THEN ''
|
|
ELSE ',""required"":[' + @required + ']'
|
|
END
|
|
+ '}';
|
|
END;
|
|
");
|
|
|
|
migrationBuilder.Sql(@"
|
|
IF OBJECT_ID('dbo.fn_LegacyReturnToJsonSchema', 'FN') IS NOT NULL
|
|
DROP FUNCTION dbo.fn_LegacyReturnToJsonSchema;
|
|
");
|
|
|
|
migrationBuilder.Sql(@"
|
|
CREATE FUNCTION dbo.fn_LegacyReturnToJsonSchema(@legacy NVARCHAR(MAX))
|
|
RETURNS NVARCHAR(MAX)
|
|
AS
|
|
BEGIN
|
|
IF @legacy IS NULL OR LTRIM(@legacy) = '' RETURN NULL;
|
|
IF LEFT(LTRIM(@legacy), 1) <> '{' RETURN @legacy;
|
|
|
|
DECLARE @legacyType NVARCHAR(50) = JSON_VALUE(@legacy, '$.type');
|
|
IF @legacyType IS NULL RETURN @legacy;
|
|
|
|
-- Already JSON Schema (lowercase types, no itemType legacy sentinel): leave it.
|
|
IF @legacyType IN ('boolean','integer','number','string','object','array')
|
|
AND JSON_VALUE(@legacy, '$.itemType') IS NULL
|
|
RETURN @legacy;
|
|
|
|
IF LOWER(@legacyType) = 'list'
|
|
BEGIN
|
|
DECLARE @inner NVARCHAR(50) =
|
|
dbo.fn_LegacyTypeToJsonSchemaType(JSON_VALUE(@legacy, '$.itemType'));
|
|
RETURN CONCAT('{""type"":""array"",""items"":{""type"":""', @inner, '""}}');
|
|
END;
|
|
|
|
RETURN CONCAT('{""type"":""', dbo.fn_LegacyTypeToJsonSchemaType(@legacyType), '""}');
|
|
END;
|
|
");
|
|
|
|
migrationBuilder.Sql(@"
|
|
UPDATE TemplateScripts
|
|
SET ParameterDefinitions = dbo.fn_LegacyParametersToJsonSchema(ParameterDefinitions)
|
|
WHERE ParameterDefinitions IS NOT NULL
|
|
AND LEFT(LTRIM(ParameterDefinitions), 1) = '[';
|
|
|
|
UPDATE TemplateScripts
|
|
SET ReturnDefinition = dbo.fn_LegacyReturnToJsonSchema(ReturnDefinition)
|
|
WHERE ReturnDefinition IS NOT NULL
|
|
AND LEFT(LTRIM(ReturnDefinition), 1) = '{';
|
|
|
|
UPDATE SharedScripts
|
|
SET ParameterDefinitions = dbo.fn_LegacyParametersToJsonSchema(ParameterDefinitions)
|
|
WHERE ParameterDefinitions IS NOT NULL
|
|
AND LEFT(LTRIM(ParameterDefinitions), 1) = '[';
|
|
|
|
UPDATE SharedScripts
|
|
SET ReturnDefinition = dbo.fn_LegacyReturnToJsonSchema(ReturnDefinition)
|
|
WHERE ReturnDefinition IS NOT NULL
|
|
AND LEFT(LTRIM(ReturnDefinition), 1) = '{';
|
|
|
|
UPDATE ApiMethods
|
|
SET ParameterDefinitions = dbo.fn_LegacyParametersToJsonSchema(ParameterDefinitions)
|
|
WHERE ParameterDefinitions IS NOT NULL
|
|
AND LEFT(LTRIM(ParameterDefinitions), 1) = '[';
|
|
|
|
UPDATE ApiMethods
|
|
SET ReturnDefinition = dbo.fn_LegacyReturnToJsonSchema(ReturnDefinition)
|
|
WHERE ReturnDefinition IS NOT NULL
|
|
AND LEFT(LTRIM(ReturnDefinition), 1) = '{';
|
|
");
|
|
|
|
migrationBuilder.Sql(@"
|
|
DROP FUNCTION IF EXISTS dbo.fn_LegacyParametersToJsonSchema;
|
|
DROP FUNCTION IF EXISTS dbo.fn_LegacyReturnToJsonSchema;
|
|
DROP FUNCTION IF EXISTS dbo.fn_LegacyTypeToJsonSchemaType;
|
|
");
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
protected override void Down(MigrationBuilder migrationBuilder)
|
|
{
|
|
// Lossy: JSON Schema can express fields (descriptions, defaults, enums,
|
|
// nested objects) that the legacy flat shape cannot represent. Reverse
|
|
// migration is not supported.
|
|
throw new System.NotSupportedException(
|
|
"Reverse migration from JSON Schema to legacy flat shape is not supported because the conversion is lossy.");
|
|
}
|
|
}
|
|
}
|