mirror of
https://github.com/modrinth/code.git
synced 2026-08-30 19:46:33 +00:00
adjust schema
This commit is contained in:
@@ -461,10 +461,16 @@ const TEST_INPUTS: Labrinth.TechReview.Internal.RuleInput[] = [
|
||||
sha512: 'fedcba9876543210',
|
||||
},
|
||||
},
|
||||
scope: {
|
||||
project_id: 'example-project',
|
||||
version_id: 'example-version',
|
||||
file_id: 'example-file',
|
||||
project: {
|
||||
id: 'example-project',
|
||||
types: ['mod'],
|
||||
},
|
||||
version: {
|
||||
id: 'example-version',
|
||||
loaders: ['fabric'],
|
||||
},
|
||||
file: {
|
||||
id: 'example-file',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -489,10 +495,16 @@ const TEST_INPUTS: Labrinth.TechReview.Internal.RuleInput[] = [
|
||||
sha512: '0123456789abcdef',
|
||||
},
|
||||
},
|
||||
scope: {
|
||||
project_id: 'telemetry-project',
|
||||
version_id: 'telemetry-version',
|
||||
file_id: 'telemetry-file',
|
||||
project: {
|
||||
id: 'telemetry-project',
|
||||
types: ['mod'],
|
||||
},
|
||||
version: {
|
||||
id: 'telemetry-version',
|
||||
loaders: ['neoforge'],
|
||||
},
|
||||
file: {
|
||||
id: 'telemetry-file',
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
Generated
+22
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT COUNT(*) FROM payouts_values_notifications WHERE notified = FALSE AND user_id = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "count",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "0f3d943e4fc48a94363b77c8a7d36eb1dd626e77331d8278c406df952691be4c"
|
||||
}
|
||||
Generated
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO users (id, username, email, role)\n VALUES\n (1000, 'userland', 'userland@modrinth.com', 'developer'),\n (1001, 'useful', 'useful@modrinth.com', 'developer'),\n (1002, 'Useless', 'useless@modrinth.com', 'developer')\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "0ffebf149d50149d0c128478e6267a2296efc16763cdbd5d8c295a1a7ca08021"
|
||||
}
|
||||
Generated
+32
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT id AS \"id!: DelphiRuleId\", name, rule\n FROM delphi_rules\n WHERE NOT delete_on_next_revision\n ORDER BY priority DESC, id\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id!: DelphiRuleId",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "name",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "rule",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "182be4110f45b6be6a9174200a07a887cebbaeab0a8c1da8b008e0c5e94fbc4e"
|
||||
}
|
||||
Generated
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n id,\n status AS \"status: PayoutStatus\"\n FROM payouts\n ORDER BY id\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "status: PayoutStatus",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "1adbd24d815107e13bc1440c7a8f4eeff66ab4165a9f4980032e114db4dc1286"
|
||||
}
|
||||
Generated
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT COUNT(*) FROM payouts_values_notifications WHERE notified = FALSE",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "count",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "20cff8fdf7971e91c9d473b9a4663ce02ca16781e32232ae0fa7a0af1973d3a4"
|
||||
}
|
||||
Generated
+14
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE mods SET status = 'processing' WHERE id = $1",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "329c009635ad2a4c214da2f4651b8c14fe329deac983bc2f43ba74e066f9cf8d"
|
||||
}
|
||||
Generated
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO users (id, username, email, role)\n VALUES (2100, 'prefix_under_score', 'prefix_under_score@modrinth.com', 'developer')\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "38ace0abad724d1111b79a72c7c8518f1272690ce7766dbdc41ec1e98f7f1fec"
|
||||
}
|
||||
Generated
-26
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT id AS \"id!: DelphiRuleId\", rule\n FROM delphi_rules\n WHERE NOT delete_on_next_revision\n ORDER BY priority DESC, id\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id!: DelphiRuleId",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "rule",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "3f1aaeed6e394294fa32da7e7f83765fb64bd9499a796470d544466886e1a808"
|
||||
}
|
||||
Generated
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO users (id, username, email, role)\n VALUES ($1, $2, $3, 'developer')\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8",
|
||||
"Varchar",
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "5cb65218a2a4a7343130d838f8a78df08d25844f1019d539712b0cb686e4ae81"
|
||||
}
|
||||
Generated
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO payouts_values_notifications (date_available, user_id, notified)\n VALUES ($1, $2, FALSE)\n ON CONFLICT (date_available, user_id) DO NOTHING",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Timestamptz",
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "6678cd4c51771cfaae2be8021ba66908ea41a06ba858dc5b523aef6aae27b850"
|
||||
}
|
||||
Generated
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "CREATE SCHEMA public;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "66868d0b35229abffa3f668eaef19dc0cdef502935dd5939a2f3ab89b0766ad2"
|
||||
}
|
||||
Generated
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO payouts_values (user_id, mod_id, amount, created, date_available)\n VALUES ($1, NULL, $2, NOW(), $3)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8",
|
||||
"Numeric",
|
||||
"Timestamptz"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "69a1cb4b7f1115a990d1fc4805d58541fc78e910111c09ba3d50a12d9ca4a9f8"
|
||||
}
|
||||
+14
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n detail.id,\n detail.key,\n issue.issue_type,\n detail.severity AS \"severity: DelphiSeverity\",\n detail.jar,\n detail.file_path,\n detail.data AS \"data: Json<HashMap<String, serde_json::Value>>\",\n report.delphi_version,\n file.size AS \"size?\",\n file.id AS \"file_id?\",\n version.id AS \"version_id?\",\n version.mod_id AS \"project_id?\",\n COALESCE(file_hashes.hashes, '{}'::jsonb)\n AS \"hashes!: Json<BTreeMap<String, String>>\"\n FROM delphi_report_issue_details detail\n INNER JOIN delphi_report_issues issue ON issue.id = detail.issue_id\n INNER JOIN delphi_reports report ON report.id = issue.report_id\n LEFT JOIN files file ON file.id = report.file_id\n LEFT JOIN versions version ON version.id = file.version_id\n LEFT JOIN LATERAL (\n SELECT\n jsonb_object_agg(algorithm, encode(hash, 'hex')) AS hashes\n FROM hashes\n WHERE hashes.file_id = file.id\n ) file_hashes ON TRUE\n WHERE detail.id = ANY($1::bigint[])\n ORDER BY detail.id\n ",
|
||||
"query": "\n SELECT\n detail.id,\n detail.key,\n issue.issue_type,\n detail.severity AS \"severity: DelphiSeverity\",\n detail.jar,\n detail.file_path,\n detail.data AS \"data: Json<HashMap<String, serde_json::Value>>\",\n report.delphi_version,\n file.size AS \"size?\",\n file.id AS \"file_id?\",\n version.id AS \"version_id?\",\n version.mod_id AS \"project_id?\",\n COALESCE(version_metadata.project_types, ARRAY[]::text[])\n AS \"project_types!: Vec<String>\",\n COALESCE(version_metadata.loaders, ARRAY[]::text[])\n AS \"loaders!: Vec<String>\",\n COALESCE(file_hashes.hashes, '{}'::jsonb)\n AS \"hashes!: Json<BTreeMap<String, String>>\"\n FROM delphi_report_issue_details detail\n INNER JOIN delphi_report_issues issue ON issue.id = detail.issue_id\n INNER JOIN delphi_reports report ON report.id = issue.report_id\n LEFT JOIN files file ON file.id = report.file_id\n LEFT JOIN versions version ON version.id = file.version_id\n LEFT JOIN LATERAL (\n SELECT\n ARRAY_AGG(\n DISTINCT project_type.name::text\n ORDER BY project_type.name::text\n ) FILTER (WHERE project_type.name IS NOT NULL)\n AS project_types,\n ARRAY_AGG(\n DISTINCT loader.loader\n ORDER BY loader.loader\n ) AS loaders\n FROM loaders_versions loader_version\n INNER JOIN loaders loader\n ON loader.id = loader_version.loader_id\n LEFT JOIN loaders_project_types loader_project_type\n ON loader_project_type.joining_loader_id = loader_version.loader_id\n LEFT JOIN project_types project_type\n ON project_type.id = loader_project_type.joining_project_type_id\n WHERE loader_version.version_id = version.id\n ) version_metadata ON TRUE\n LEFT JOIN LATERAL (\n SELECT\n jsonb_object_agg(algorithm, encode(hash, 'hex')) AS hashes\n FROM hashes\n WHERE hashes.file_id = file.id\n ) file_hashes ON TRUE\n WHERE detail.id = ANY($1::bigint[])\n ORDER BY detail.id\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -79,6 +79,16 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"name": "project_types!: Vec<String>",
|
||||
"type_info": "TextArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"name": "loaders!: Vec<String>",
|
||||
"type_info": "VarcharArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"name": "hashes!: Json<BTreeMap<String, String>>",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
@@ -101,8 +111,10 @@
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "868d19328921b9a3bd56fa9354e5e75d09c76a3eb3ed9c89b05b9aab13505bf9"
|
||||
"hash": "7e7e2e9f67158b94eb62834cbfd65fd5165d02ebcc0f8454554cbd870e4ddb42"
|
||||
}
|
||||
+14
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n detail.id,\n detail.key,\n issue.issue_type,\n detail.severity AS \"severity: DelphiSeverity\",\n detail.jar,\n detail.file_path,\n detail.data AS \"data: Json<HashMap<String, serde_json::Value>>\",\n report.delphi_version,\n file.size AS \"size?\",\n file.id AS \"file_id?\",\n version.id AS \"version_id?\",\n version.mod_id AS \"project_id?\",\n COALESCE(file_hashes.hashes, '{}'::jsonb)\n AS \"hashes!: Json<BTreeMap<String, String>>\"\n FROM delphi_report_issue_details detail\n INNER JOIN delphi_report_issues issue ON issue.id = detail.issue_id\n INNER JOIN delphi_reports report ON report.id = issue.report_id\n LEFT JOIN files file ON file.id = report.file_id\n LEFT JOIN versions version ON version.id = file.version_id\n LEFT JOIN (\n SELECT\n file_id,\n jsonb_object_agg(algorithm, encode(hash, 'hex')) AS hashes\n FROM hashes\n GROUP BY file_id\n ) file_hashes ON file_hashes.file_id = file.id\n ORDER BY detail.id\n ",
|
||||
"query": "\n SELECT\n detail.id,\n detail.key,\n issue.issue_type,\n detail.severity AS \"severity: DelphiSeverity\",\n detail.jar,\n detail.file_path,\n detail.data AS \"data: Json<HashMap<String, serde_json::Value>>\",\n report.delphi_version,\n file.size AS \"size?\",\n file.id AS \"file_id?\",\n version.id AS \"version_id?\",\n version.mod_id AS \"project_id?\",\n COALESCE(version_metadata.project_types, ARRAY[]::text[])\n AS \"project_types!: Vec<String>\",\n COALESCE(version_metadata.loaders, ARRAY[]::text[])\n AS \"loaders!: Vec<String>\",\n COALESCE(file_hashes.hashes, '{}'::jsonb)\n AS \"hashes!: Json<BTreeMap<String, String>>\"\n FROM delphi_report_issue_details detail\n INNER JOIN delphi_report_issues issue ON issue.id = detail.issue_id\n INNER JOIN delphi_reports report ON report.id = issue.report_id\n LEFT JOIN files file ON file.id = report.file_id\n LEFT JOIN versions version ON version.id = file.version_id\n LEFT JOIN (\n SELECT\n loader_version.version_id,\n ARRAY_AGG(\n DISTINCT project_type.name::text\n ORDER BY project_type.name::text\n ) FILTER (WHERE project_type.name IS NOT NULL)\n AS project_types,\n ARRAY_AGG(\n DISTINCT loader.loader\n ORDER BY loader.loader\n ) AS loaders\n FROM loaders_versions loader_version\n INNER JOIN loaders loader\n ON loader.id = loader_version.loader_id\n LEFT JOIN loaders_project_types loader_project_type\n ON loader_project_type.joining_loader_id = loader_version.loader_id\n LEFT JOIN project_types project_type\n ON project_type.id = loader_project_type.joining_project_type_id\n GROUP BY loader_version.version_id\n ) version_metadata\n ON version_metadata.version_id = version.id\n LEFT JOIN (\n SELECT\n file_id,\n jsonb_object_agg(algorithm, encode(hash, 'hex')) AS hashes\n FROM hashes\n GROUP BY file_id\n ) file_hashes ON file_hashes.file_id = file.id\n ORDER BY detail.id\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -79,6 +79,16 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"name": "project_types!: Vec<String>",
|
||||
"type_info": "TextArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"name": "loaders!: Vec<String>",
|
||||
"type_info": "VarcharArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"name": "hashes!: Json<BTreeMap<String, String>>",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
@@ -99,8 +109,10 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "2fb03e1de120cf921146b6dbd35691117412407c4225f966c013fdfef21a82fb"
|
||||
"hash": "8537362d9c11e437ada9ce97bb604666378d1d24981ab8113badded16fb63413"
|
||||
}
|
||||
Generated
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE moderation_locks SET locked_at = NOW() - ($1::bigint * INTERVAL '1 minute') - INTERVAL '1 second' WHERE project_id = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8",
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "8ca7f46618bd72cfd5fe1f246d41a31da1885cc22bb61be6853950ba52be9aa7"
|
||||
}
|
||||
+14
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n detail.key,\n issue.issue_type,\n detail.severity AS \"severity: DelphiSeverity\",\n detail.jar,\n detail.file_path,\n detail.data AS \"data: Json<HashMap<String, serde_json::Value>>\",\n report.delphi_version,\n file.size AS \"size?\",\n file.id AS \"file_id?\",\n version.id AS \"version_id?\",\n version.mod_id AS \"project_id?\",\n COALESCE(file_hashes.hashes, '{}'::jsonb)\n AS \"hashes!: Json<BTreeMap<String, String>>\"\n FROM delphi_report_issue_details detail\n INNER JOIN delphi_report_issues issue ON issue.id = detail.issue_id\n INNER JOIN delphi_reports report ON report.id = issue.report_id\n LEFT JOIN files file ON file.id = report.file_id\n LEFT JOIN versions version ON version.id = file.version_id\n LEFT JOIN LATERAL (\n SELECT\n jsonb_object_agg(algorithm, encode(hash, 'hex')) AS hashes\n FROM hashes\n WHERE hashes.file_id = file.id\n ) file_hashes ON TRUE\n WHERE detail.id = $1\n ",
|
||||
"query": "\n SELECT\n detail.key,\n issue.issue_type,\n detail.severity AS \"severity: DelphiSeverity\",\n detail.jar,\n detail.file_path,\n detail.data AS \"data: Json<HashMap<String, serde_json::Value>>\",\n report.delphi_version,\n file.size AS \"size?\",\n file.id AS \"file_id?\",\n version.id AS \"version_id?\",\n version.mod_id AS \"project_id?\",\n COALESCE(version_metadata.project_types, ARRAY[]::text[])\n AS \"project_types!: Vec<String>\",\n COALESCE(version_metadata.loaders, ARRAY[]::text[])\n AS \"loaders!: Vec<String>\",\n COALESCE(file_hashes.hashes, '{}'::jsonb)\n AS \"hashes!: Json<BTreeMap<String, String>>\"\n FROM delphi_report_issue_details detail\n INNER JOIN delphi_report_issues issue ON issue.id = detail.issue_id\n INNER JOIN delphi_reports report ON report.id = issue.report_id\n LEFT JOIN files file ON file.id = report.file_id\n LEFT JOIN versions version ON version.id = file.version_id\n LEFT JOIN LATERAL (\n SELECT\n ARRAY_AGG(\n DISTINCT project_type.name::text\n ORDER BY project_type.name::text\n ) FILTER (WHERE project_type.name IS NOT NULL)\n AS project_types,\n ARRAY_AGG(\n DISTINCT loader.loader\n ORDER BY loader.loader\n ) AS loaders\n FROM loaders_versions loader_version\n INNER JOIN loaders loader\n ON loader.id = loader_version.loader_id\n LEFT JOIN loaders_project_types loader_project_type\n ON loader_project_type.joining_loader_id = loader_version.loader_id\n LEFT JOIN project_types project_type\n ON project_type.id = loader_project_type.joining_project_type_id\n WHERE loader_version.version_id = version.id\n ) version_metadata ON TRUE\n LEFT JOIN LATERAL (\n SELECT\n jsonb_object_agg(algorithm, encode(hash, 'hex')) AS hashes\n FROM hashes\n WHERE hashes.file_id = file.id\n ) file_hashes ON TRUE\n WHERE detail.id = $1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -74,6 +74,16 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"name": "project_types!: Vec<String>",
|
||||
"type_info": "TextArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"name": "loaders!: Vec<String>",
|
||||
"type_info": "VarcharArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"name": "hashes!: Json<BTreeMap<String, String>>",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
@@ -95,8 +105,10 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "1f318b0dda5aaf58b9e403f87fcacfcd223bd67f6d5ba95868ace4373a98c67d"
|
||||
"hash": "b536d7870ba77ace55e309938c3ba93c7016b2a6f18aa4f22ea57f604d82c1da"
|
||||
}
|
||||
Generated
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT status AS \"status: PayoutStatus\" FROM payouts WHERE id = 1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "status: PayoutStatus",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "b92b5bb7d179c4fcdbc45600ccfd2402f52fea71e27b08e7926fcc2a9e62c0f3"
|
||||
}
|
||||
Generated
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "DROP SCHEMA public CASCADE;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "c65295f61b18f7be4fdf30b3e2c2c36b9db3770508be4acbb6b441ed8006d9c7"
|
||||
}
|
||||
Generated
+14
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE users SET email_verified = TRUE WHERE id = $1",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "cb626a36deffd73e67de2dc4789bd875675779a173fb2cd41ba365c1acca96f9"
|
||||
}
|
||||
Generated
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO payouts (id, method, platform_id, status, user_id, amount, created)\n VALUES ($1, $2, $3, $4, $5, 10.0, NOW())\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8",
|
||||
"Text",
|
||||
"Text",
|
||||
"Varchar",
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "cd5ccd618fb3cc41646a6de86f9afedb074492b4ec7f2457c14113f5fd13aa02"
|
||||
}
|
||||
Generated
+17
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO payouts (id, method, platform_id, status, user_id, amount, created)\n VALUES ($1, $2, NULL, $3, $4, 10.00, NOW())\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8",
|
||||
"Text",
|
||||
"Varchar",
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "cec4240c7c848988b3dfd13e3f8e5c93783c7641b019fdb698a1ec0be1393606"
|
||||
}
|
||||
Generated
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT pg_advisory_unlock(1)",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "pg_advisory_unlock",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "fabba52b34e14196b6305671c060d934b9afc6dccc5fc77454fbe45365bdf429"
|
||||
}
|
||||
Generated
+22
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT COUNT(*) FROM notifications WHERE user_id = $1 AND body->>'type' = 'payout_available'",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "count",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "fd5c773a61d35bcd71503ec4d5f86e8917cfab9679d5064074681663ba467e41"
|
||||
}
|
||||
@@ -158,8 +158,9 @@ pub async fn test_rule(
|
||||
})?;
|
||||
|
||||
let rule = request.rule;
|
||||
let expression = rule.clone();
|
||||
let program =
|
||||
tokio::task::spawn_blocking(move || cel::Program::compile(&rule))
|
||||
tokio::task::spawn_blocking(move || cel::Program::compile(&expression))
|
||||
.await
|
||||
.wrap_internal_err("failed to join cel compilation task")?
|
||||
.map_err(|error| {
|
||||
@@ -168,12 +169,11 @@ pub async fn test_rule(
|
||||
let mut effects = Vec::with_capacity(request.inputs.len());
|
||||
|
||||
for (index, input) in request.inputs.iter().enumerate() {
|
||||
let effect = super::rules_scan::evaluate_rule(&program, input)
|
||||
.map_err(|error| {
|
||||
ApiError::Request(eyre!(
|
||||
"failed to evaluate test input {index}: {error}"
|
||||
))
|
||||
})?;
|
||||
let evaluation =
|
||||
super::rules_scan::evaluate_rule(&program, &rule, input);
|
||||
let effect = evaluation.wrap_request_err(format!(
|
||||
"failed to evaluate test input {index}"
|
||||
))?;
|
||||
effects.push(effect);
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,9 @@ pub struct RuleInput {
|
||||
pub trace: RuleTrace,
|
||||
pub scan: RuleScan,
|
||||
pub artifact: RuleArtifact,
|
||||
pub scope: RuleScope,
|
||||
pub project: RuleProject,
|
||||
pub version: RuleVersion,
|
||||
pub file: RuleFile,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, utoipa::ToSchema)]
|
||||
@@ -83,14 +85,26 @@ pub struct RuleArtifact {
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, utoipa::ToSchema)]
|
||||
pub struct RuleScope {
|
||||
pub project_id: Option<String>,
|
||||
pub version_id: Option<String>,
|
||||
pub file_id: Option<String>,
|
||||
pub struct RuleProject {
|
||||
pub id: Option<String>,
|
||||
pub types: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, utoipa::ToSchema)]
|
||||
pub struct RuleVersion {
|
||||
pub id: Option<String>,
|
||||
pub loaders: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, utoipa::ToSchema)]
|
||||
pub struct RuleFile {
|
||||
pub id: Option<String>,
|
||||
}
|
||||
|
||||
struct CompiledRule {
|
||||
id: DelphiRuleId,
|
||||
name: String,
|
||||
expression: String,
|
||||
program: cel::Program,
|
||||
}
|
||||
|
||||
@@ -197,6 +211,10 @@ pub async fn get_detail_rule_input(
|
||||
file.id AS "file_id?",
|
||||
version.id AS "version_id?",
|
||||
version.mod_id AS "project_id?",
|
||||
COALESCE(version_metadata.project_types, ARRAY[]::text[])
|
||||
AS "project_types!: Vec<String>",
|
||||
COALESCE(version_metadata.loaders, ARRAY[]::text[])
|
||||
AS "loaders!: Vec<String>",
|
||||
COALESCE(file_hashes.hashes, '{}'::jsonb)
|
||||
AS "hashes!: Json<BTreeMap<String, String>>"
|
||||
FROM delphi_report_issue_details detail
|
||||
@@ -204,6 +222,26 @@ pub async fn get_detail_rule_input(
|
||||
INNER JOIN delphi_reports report ON report.id = issue.report_id
|
||||
LEFT JOIN files file ON file.id = report.file_id
|
||||
LEFT JOIN versions version ON version.id = file.version_id
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT
|
||||
ARRAY_AGG(
|
||||
DISTINCT project_type.name::text
|
||||
ORDER BY project_type.name::text
|
||||
) FILTER (WHERE project_type.name IS NOT NULL)
|
||||
AS project_types,
|
||||
ARRAY_AGG(
|
||||
DISTINCT loader.loader
|
||||
ORDER BY loader.loader
|
||||
) AS loaders
|
||||
FROM loaders_versions loader_version
|
||||
INNER JOIN loaders loader
|
||||
ON loader.id = loader_version.loader_id
|
||||
LEFT JOIN loaders_project_types loader_project_type
|
||||
ON loader_project_type.joining_loader_id = loader_version.loader_id
|
||||
LEFT JOIN project_types project_type
|
||||
ON project_type.id = loader_project_type.joining_project_type_id
|
||||
WHERE loader_version.version_id = version.id
|
||||
) version_metadata ON TRUE
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT
|
||||
jsonb_object_agg(algorithm, encode(hash, 'hex')) AS hashes
|
||||
@@ -237,10 +275,16 @@ pub async fn get_detail_rule_input(
|
||||
size: detail.size,
|
||||
hashes: detail.hashes.0,
|
||||
},
|
||||
scope: RuleScope {
|
||||
project_id: detail.project_id.map(|id| to_base62(id as u64)),
|
||||
version_id: detail.version_id.map(|id| to_base62(id as u64)),
|
||||
file_id: detail.file_id.map(|id| to_base62(id as u64)),
|
||||
project: RuleProject {
|
||||
id: detail.project_id.map(|id| to_base62(id as u64)),
|
||||
types: detail.project_types,
|
||||
},
|
||||
version: RuleVersion {
|
||||
id: detail.version_id.map(|id| to_base62(id as u64)),
|
||||
loaders: detail.loaders,
|
||||
},
|
||||
file: RuleFile {
|
||||
id: detail.file_id.map(|id| to_base62(id as u64)),
|
||||
},
|
||||
}))
|
||||
}
|
||||
@@ -331,7 +375,7 @@ pub async fn scan_rules(
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::error!(error = ?error, "delphi rule scan failed");
|
||||
let message = error.to_string();
|
||||
let message = format!("{error:#}");
|
||||
let event = RuleScanErrorEvent { message: &message };
|
||||
if let Ok(data) = serde_json::to_string(&event) {
|
||||
let _ = sender.send(Bytes::from(format!(
|
||||
@@ -402,6 +446,10 @@ async fn run_scan(
|
||||
file.id AS "file_id?",
|
||||
version.id AS "version_id?",
|
||||
version.mod_id AS "project_id?",
|
||||
COALESCE(version_metadata.project_types, ARRAY[]::text[])
|
||||
AS "project_types!: Vec<String>",
|
||||
COALESCE(version_metadata.loaders, ARRAY[]::text[])
|
||||
AS "loaders!: Vec<String>",
|
||||
COALESCE(file_hashes.hashes, '{}'::jsonb)
|
||||
AS "hashes!: Json<BTreeMap<String, String>>"
|
||||
FROM delphi_report_issue_details detail
|
||||
@@ -409,6 +457,28 @@ async fn run_scan(
|
||||
INNER JOIN delphi_reports report ON report.id = issue.report_id
|
||||
LEFT JOIN files file ON file.id = report.file_id
|
||||
LEFT JOIN versions version ON version.id = file.version_id
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
loader_version.version_id,
|
||||
ARRAY_AGG(
|
||||
DISTINCT project_type.name::text
|
||||
ORDER BY project_type.name::text
|
||||
) FILTER (WHERE project_type.name IS NOT NULL)
|
||||
AS project_types,
|
||||
ARRAY_AGG(
|
||||
DISTINCT loader.loader
|
||||
ORDER BY loader.loader
|
||||
) AS loaders
|
||||
FROM loaders_versions loader_version
|
||||
INNER JOIN loaders loader
|
||||
ON loader.id = loader_version.loader_id
|
||||
LEFT JOIN loaders_project_types loader_project_type
|
||||
ON loader_project_type.joining_loader_id = loader_version.loader_id
|
||||
LEFT JOIN project_types project_type
|
||||
ON project_type.id = loader_project_type.joining_project_type_id
|
||||
GROUP BY loader_version.version_id
|
||||
) version_metadata
|
||||
ON version_metadata.version_id = version.id
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
file_id,
|
||||
@@ -458,19 +528,29 @@ async fn run_scan(
|
||||
size: detail.size,
|
||||
hashes: detail.hashes.0,
|
||||
},
|
||||
scope: RuleScope {
|
||||
project_id: detail.project_id.map(|id| to_base62(id as u64)),
|
||||
version_id: detail.version_id.map(|id| to_base62(id as u64)),
|
||||
file_id: detail.file_id.map(|id| to_base62(id as u64)),
|
||||
project: RuleProject {
|
||||
id: detail.project_id.map(|id| to_base62(id as u64)),
|
||||
types: detail.project_types,
|
||||
},
|
||||
version: RuleVersion {
|
||||
id: detail.version_id.map(|id| to_base62(id as u64)),
|
||||
loaders: detail.loaders,
|
||||
},
|
||||
file: RuleFile {
|
||||
id: detail.file_id.map(|id| to_base62(id as u64)),
|
||||
},
|
||||
};
|
||||
|
||||
for rule in &rules {
|
||||
let effect = evaluate_rule(&rule.program, &input)
|
||||
let effect = evaluate_rule(
|
||||
&rule.program,
|
||||
&rule.expression,
|
||||
&input,
|
||||
)
|
||||
.wrap_err_with(|| {
|
||||
format!(
|
||||
"failed to evaluate delphi rule {} for detail {detail_id}",
|
||||
rule.id.0
|
||||
"failed to evaluate delphi rule '{}' for detail {detail_id}",
|
||||
rule.name
|
||||
)
|
||||
})?;
|
||||
if let Some(effect) = effect {
|
||||
@@ -642,6 +722,10 @@ pub(crate) async fn materialize_current_rule_effects(
|
||||
file.id AS "file_id?",
|
||||
version.id AS "version_id?",
|
||||
version.mod_id AS "project_id?",
|
||||
COALESCE(version_metadata.project_types, ARRAY[]::text[])
|
||||
AS "project_types!: Vec<String>",
|
||||
COALESCE(version_metadata.loaders, ARRAY[]::text[])
|
||||
AS "loaders!: Vec<String>",
|
||||
COALESCE(file_hashes.hashes, '{}'::jsonb)
|
||||
AS "hashes!: Json<BTreeMap<String, String>>"
|
||||
FROM delphi_report_issue_details detail
|
||||
@@ -649,6 +733,26 @@ pub(crate) async fn materialize_current_rule_effects(
|
||||
INNER JOIN delphi_reports report ON report.id = issue.report_id
|
||||
LEFT JOIN files file ON file.id = report.file_id
|
||||
LEFT JOIN versions version ON version.id = file.version_id
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT
|
||||
ARRAY_AGG(
|
||||
DISTINCT project_type.name::text
|
||||
ORDER BY project_type.name::text
|
||||
) FILTER (WHERE project_type.name IS NOT NULL)
|
||||
AS project_types,
|
||||
ARRAY_AGG(
|
||||
DISTINCT loader.loader
|
||||
ORDER BY loader.loader
|
||||
) AS loaders
|
||||
FROM loaders_versions loader_version
|
||||
INNER JOIN loaders loader
|
||||
ON loader.id = loader_version.loader_id
|
||||
LEFT JOIN loaders_project_types loader_project_type
|
||||
ON loader_project_type.joining_loader_id = loader_version.loader_id
|
||||
LEFT JOIN project_types project_type
|
||||
ON project_type.id = loader_project_type.joining_project_type_id
|
||||
WHERE loader_version.version_id = version.id
|
||||
) version_metadata ON TRUE
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT
|
||||
jsonb_object_agg(algorithm, encode(hash, 'hex')) AS hashes
|
||||
@@ -683,19 +787,25 @@ pub(crate) async fn materialize_current_rule_effects(
|
||||
size: detail.size,
|
||||
hashes: detail.hashes.0,
|
||||
},
|
||||
scope: RuleScope {
|
||||
project_id: detail.project_id.map(|id| to_base62(id as u64)),
|
||||
version_id: detail.version_id.map(|id| to_base62(id as u64)),
|
||||
file_id: detail.file_id.map(|id| to_base62(id as u64)),
|
||||
project: RuleProject {
|
||||
id: detail.project_id.map(|id| to_base62(id as u64)),
|
||||
types: detail.project_types,
|
||||
},
|
||||
version: RuleVersion {
|
||||
id: detail.version_id.map(|id| to_base62(id as u64)),
|
||||
loaders: detail.loaders,
|
||||
},
|
||||
file: RuleFile {
|
||||
id: detail.file_id.map(|id| to_base62(id as u64)),
|
||||
},
|
||||
};
|
||||
|
||||
for rule in &rules {
|
||||
let effect =
|
||||
evaluate_rule(&rule.program, &input).wrap_err_with(|| {
|
||||
let effect = evaluate_rule(&rule.program, &rule.expression, &input)
|
||||
.wrap_err_with(|| {
|
||||
format!(
|
||||
"failed to evaluate delphi rule {} for detail {}",
|
||||
rule.id.0, detail.id
|
||||
"failed to evaluate delphi rule '{}' for detail {}",
|
||||
rule.name, detail.id
|
||||
)
|
||||
})?;
|
||||
if let Some(effect) = effect {
|
||||
@@ -717,7 +827,7 @@ async fn fetch_compiled_rules(
|
||||
) -> Result<Vec<CompiledRule>> {
|
||||
let rules = sqlx::query!(
|
||||
r#"
|
||||
SELECT id AS "id!: DelphiRuleId", rule
|
||||
SELECT id AS "id!: DelphiRuleId", name, rule
|
||||
FROM delphi_rules
|
||||
WHERE NOT delete_on_next_revision
|
||||
ORDER BY priority DESC, id
|
||||
@@ -734,12 +844,14 @@ async fn fetch_compiled_rules(
|
||||
let program =
|
||||
cel::Program::compile(&rule.rule).map_err(|error| {
|
||||
eyre!(
|
||||
"failed to compile delphi rule {}: {error}",
|
||||
rule.id.0
|
||||
"failed to compile delphi rule '{}': {error}",
|
||||
rule.name
|
||||
)
|
||||
})?;
|
||||
Ok(CompiledRule {
|
||||
id: rule.id,
|
||||
name: rule.name,
|
||||
expression: rule.rule,
|
||||
program,
|
||||
})
|
||||
})
|
||||
@@ -799,6 +911,21 @@ async fn insert_materialized_effects(
|
||||
}
|
||||
|
||||
pub(super) fn evaluate_rule(
|
||||
program: &cel::Program,
|
||||
expression: &str,
|
||||
input: &RuleInput,
|
||||
) -> Result<Option<DelphiRuleEffect>> {
|
||||
evaluate_rule_inner(program, input)
|
||||
.wrap_err_with(|| {
|
||||
let input = serde_json::to_string(input).unwrap_or_else(|error| {
|
||||
format!("<failed to serialize CEL input: {error}>")
|
||||
});
|
||||
format!("CEL input: {input}")
|
||||
})
|
||||
.wrap_err_with(|| format!("CEL expression: {expression}"))
|
||||
}
|
||||
|
||||
fn evaluate_rule_inner(
|
||||
program: &cel::Program,
|
||||
input: &RuleInput,
|
||||
) -> Result<Option<DelphiRuleEffect>> {
|
||||
@@ -816,8 +943,14 @@ pub(super) fn evaluate_rule(
|
||||
.add_variable("artifact", &input.artifact)
|
||||
.wrap_err("failed to add `artifact` to cel context")?;
|
||||
context
|
||||
.add_variable("scope", &input.scope)
|
||||
.wrap_err("failed to add `scope` to cel context")?;
|
||||
.add_variable("project", &input.project)
|
||||
.wrap_err("failed to add `project` to cel context")?;
|
||||
context
|
||||
.add_variable("version", &input.version)
|
||||
.wrap_err("failed to add `version` to cel context")?;
|
||||
context
|
||||
.add_variable("file", &input.file)
|
||||
.wrap_err("failed to add `file` to cel context")?;
|
||||
|
||||
let value = program
|
||||
.execute(&context)
|
||||
|
||||
Reference in New Issue
Block a user