|
| 1 | +namespace NpgsqlRestTests; |
| 2 | + |
| 3 | +public static partial class Database |
| 4 | +{ |
| 5 | + public static void CommentSingleTests() |
| 6 | + { |
| 7 | + script.Append(@" |
| 8 | +-- Single record from a function returning SETOF (multiple rows, but @single returns only first as object) |
| 9 | +create function comment_single_setof() returns setof text language sql as |
| 10 | +'select ''row1'' union all select ''row2'' union all select ''row3'''; |
| 11 | +comment on function comment_single_setof() is 'HTTP GET |
| 12 | +@single'; |
| 13 | +
|
| 14 | +-- Single record from a function returning a table (multi-column, returns object not array) |
| 15 | +create function comment_single_table() |
| 16 | +returns table(id int, name text) language sql as |
| 17 | +'select 1, ''alice'' union all select 2, ''bob'''; |
| 18 | +comment on function comment_single_table() is 'HTTP GET |
| 19 | +@single'; |
| 20 | +
|
| 21 | +-- Single record from a function that naturally returns one row (SETOF with one result) |
| 22 | +create function comment_single_one_row() returns setof text language sql as |
| 23 | +'select ''only_one'''; |
| 24 | +comment on function comment_single_one_row() is 'HTTP GET |
| 25 | +@single'; |
| 26 | +
|
| 27 | +-- Without @single for comparison (returns array) |
| 28 | +create function comment_no_single_setof() returns setof text language sql as |
| 29 | +'select ''row1'' union all select ''row2'''; |
| 30 | +comment on function comment_no_single_setof() is 'HTTP GET'; |
| 31 | +
|
| 32 | +-- Single with single_record alias |
| 33 | +create function comment_single_record_alias() returns setof text language sql as |
| 34 | +'select ''alias_result'''; |
| 35 | +comment on function comment_single_record_alias() is 'HTTP GET |
| 36 | +@single_record'; |
| 37 | +
|
| 38 | +-- Single record from a function returning table with multiple rows - verifies early exit |
| 39 | +create function comment_single_multi_row_table() |
| 40 | +returns table(id int, val text) language sql as |
| 41 | +'select generate_series(1, 100), ''item_'' || generate_series(1, 100)'; |
| 42 | +comment on function comment_single_multi_row_table() is 'HTTP GET |
| 43 | +single'; |
| 44 | +
|
| 45 | +-- Single record from a function returning table with one column (named, ReturnsUnnamedSet=false) |
| 46 | +-- Should return object not bare value |
| 47 | +create function comment_single_named_column() |
| 48 | +returns table(val text) language sql as |
| 49 | +'select ''hello'''; |
| 50 | +comment on function comment_single_named_column() is 'HTTP GET |
| 51 | +@single'; |
| 52 | +
|
| 53 | +-- Single with empty result, default null handling (empty string) |
| 54 | +create function comment_single_empty_default() |
| 55 | +returns table(id int, name text) language sql as |
| 56 | +'select id, name from (select 1 as id, ''x'' as name) t where false'; |
| 57 | +comment on function comment_single_empty_default() is 'HTTP GET |
| 58 | +@single'; |
| 59 | +
|
| 60 | +-- Single with empty result, null_literal handling |
| 61 | +create function comment_single_empty_null_literal() |
| 62 | +returns table(id int, name text) language sql as |
| 63 | +'select id, name from (select 1 as id, ''x'' as name) t where false'; |
| 64 | +comment on function comment_single_empty_null_literal() is 'HTTP GET |
| 65 | +@single |
| 66 | +response_null null_literal'; |
| 67 | +
|
| 68 | +-- Single with empty result, no_content handling (204) |
| 69 | +create function comment_single_empty_no_content() |
| 70 | +returns table(id int, name text) language sql as |
| 71 | +'select id, name from (select 1 as id, ''x'' as name) t where false'; |
| 72 | +comment on function comment_single_empty_no_content() is 'HTTP GET |
| 73 | +@single |
| 74 | +response_null no_content'; |
| 75 | +
|
| 76 | +"); |
| 77 | + } |
| 78 | +} |
| 79 | + |
| 80 | +[Collection("TestFixture")] |
| 81 | +public class CommentSingleTests(TestFixture test) |
| 82 | +{ |
| 83 | + [Fact] |
| 84 | + public async Task Test_single_setof_returns_scalar_not_array() |
| 85 | + { |
| 86 | + using var response = await test.Client.GetAsync("/api/comment-single-setof/"); |
| 87 | + var content = await response.Content.ReadAsStringAsync(); |
| 88 | + response.StatusCode.Should().Be(HttpStatusCode.OK); |
| 89 | + content.Should().Be("\"row1\""); |
| 90 | + } |
| 91 | + |
| 92 | + [Fact] |
| 93 | + public async Task Test_single_table_returns_object_not_array() |
| 94 | + { |
| 95 | + using var response = await test.Client.GetAsync("/api/comment-single-table/"); |
| 96 | + var content = await response.Content.ReadAsStringAsync(); |
| 97 | + response.StatusCode.Should().Be(HttpStatusCode.OK); |
| 98 | + content.Should().Be("{\"id\":1,\"name\":\"alice\"}"); |
| 99 | + } |
| 100 | + |
| 101 | + [Fact] |
| 102 | + public async Task Test_single_one_row_returns_scalar() |
| 103 | + { |
| 104 | + using var response = await test.Client.GetAsync("/api/comment-single-one-row/"); |
| 105 | + var content = await response.Content.ReadAsStringAsync(); |
| 106 | + response.StatusCode.Should().Be(HttpStatusCode.OK); |
| 107 | + content.Should().Be("\"only_one\""); |
| 108 | + } |
| 109 | + |
| 110 | + [Fact] |
| 111 | + public async Task Test_no_single_returns_array() |
| 112 | + { |
| 113 | + using var response = await test.Client.GetAsync("/api/comment-no-single-setof/"); |
| 114 | + var content = await response.Content.ReadAsStringAsync(); |
| 115 | + response.StatusCode.Should().Be(HttpStatusCode.OK); |
| 116 | + content.Should().Be("[\"row1\",\"row2\"]"); |
| 117 | + } |
| 118 | + |
| 119 | + [Fact] |
| 120 | + public async Task Test_single_record_alias() |
| 121 | + { |
| 122 | + using var response = await test.Client.GetAsync("/api/comment-single-record-alias/"); |
| 123 | + var content = await response.Content.ReadAsStringAsync(); |
| 124 | + response.StatusCode.Should().Be(HttpStatusCode.OK); |
| 125 | + content.Should().Be("\"alias_result\""); |
| 126 | + } |
| 127 | + |
| 128 | + [Fact] |
| 129 | + public async Task Test_single_multi_row_table_returns_only_first() |
| 130 | + { |
| 131 | + using var response = await test.Client.GetAsync("/api/comment-single-multi-row-table/"); |
| 132 | + var content = await response.Content.ReadAsStringAsync(); |
| 133 | + response.StatusCode.Should().Be(HttpStatusCode.OK); |
| 134 | + content.Should().Be("{\"id\":1,\"val\":\"item_1\"}"); |
| 135 | + } |
| 136 | + |
| 137 | + [Fact] |
| 138 | + public async Task Test_single_named_column_returns_object_not_value() |
| 139 | + { |
| 140 | + using var response = await test.Client.GetAsync("/api/comment-single-named-column/"); |
| 141 | + var content = await response.Content.ReadAsStringAsync(); |
| 142 | + response.StatusCode.Should().Be(HttpStatusCode.OK); |
| 143 | + content.Should().Be("{\"val\":\"hello\"}"); |
| 144 | + } |
| 145 | + |
| 146 | + [Fact] |
| 147 | + public async Task Test_single_empty_default_returns_empty_string() |
| 148 | + { |
| 149 | + using var response = await test.Client.GetAsync("/api/comment-single-empty-default/"); |
| 150 | + var content = await response.Content.ReadAsStringAsync(); |
| 151 | + response.StatusCode.Should().Be(HttpStatusCode.OK); |
| 152 | + content.Should().Be(""); |
| 153 | + } |
| 154 | + |
| 155 | + [Fact] |
| 156 | + public async Task Test_single_empty_null_literal_returns_null() |
| 157 | + { |
| 158 | + using var response = await test.Client.GetAsync("/api/comment-single-empty-null-literal/"); |
| 159 | + var content = await response.Content.ReadAsStringAsync(); |
| 160 | + response.StatusCode.Should().Be(HttpStatusCode.OK); |
| 161 | + content.Should().Be("null"); |
| 162 | + } |
| 163 | + |
| 164 | + [Fact] |
| 165 | + public async Task Test_single_empty_no_content_returns_204() |
| 166 | + { |
| 167 | + using var response = await test.Client.GetAsync("/api/comment-single-empty-no-content/"); |
| 168 | + response.StatusCode.Should().Be(HttpStatusCode.NoContent); |
| 169 | + } |
| 170 | +} |
0 commit comments