From e420ffe2ae57173ef6c17b6928bccf3c4853e2bd Mon Sep 17 00:00:00 2001
From: paschalisp
Date: Mon, 6 Jun 2022 00:03:08 +0400
Subject: [PATCH 1/2] Added support for varchar array fields
---
CHANGELOG.md | 3 +++
lib/src/binary_codec.dart | 13 +++++++++++++
lib/src/query.dart | 1 +
lib/src/substituter.dart | 2 ++
lib/src/types.dart | 3 +++
test/decode_test.dart | 19 ++++++++++++-------
test/encoding_test.dart | 13 +++++++++++++
test/query_test.dart | 30 ++++++++++++++++++------------
8 files changed, 65 insertions(+), 19 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6a984d32..e679b276 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
# Changelog
+## 2.4.4
+- Added support for varchar arrays.
+
## 2.4.3
- Support for clear text passwords using a boolean parameter in connection as 'allowClearTextPassword' to activate / deactivate the feature. [#20](https://github.com/isoos/postgresql-dart/pull/20).
diff --git a/lib/src/binary_codec.dart b/lib/src/binary_codec.dart
index c391898d..8234024b 100644
--- a/lib/src/binary_codec.dart
+++ b/lib/src/binary_codec.dart
@@ -254,6 +254,17 @@ class PostgresBinaryEncoder extends Converter {
'Invalid type for parameter value. Expected: List Got: ${value.runtimeType}');
}
+ case PostgreSQLDataType.varCharArray:
+ {
+ if (value is List) {
+ final bytesArray = value.map((v) => utf8.encode(v));
+ return writeListBytes>(bytesArray, 1043,
+ (item) => item.length, (writer, item) => writer.write(item));
+ }
+ throw FormatException(
+ 'Invalid type for parameter value. Expected: List Got: ${value.runtimeType}');
+ }
+
case PostgreSQLDataType.textArray:
{
if (value is List) {
@@ -487,6 +498,7 @@ class PostgresBinaryDecoder extends Converter {
case PostgreSQLDataType.integerArray:
return readListBytes(value, (reader, _) => reader.readInt32());
+ case PostgreSQLDataType.varCharArray:
case PostgreSQLDataType.textArray:
return readListBytes(value, (reader, length) {
return utf8.decode(length > 0 ? reader.read(length) : []);
@@ -555,6 +567,7 @@ class PostgresBinaryDecoder extends Converter {
701: PostgreSQLDataType.double,
1007: PostgreSQLDataType.integerArray,
1009: PostgreSQLDataType.textArray,
+ 1015: PostgreSQLDataType.varCharArray,
1043: PostgreSQLDataType.varChar,
1022: PostgreSQLDataType.doubleArray,
1082: PostgreSQLDataType.date,
diff --git a/lib/src/query.dart b/lib/src/query.dart
index 982dd95b..eb2642a6 100644
--- a/lib/src/query.dart
+++ b/lib/src/query.dart
@@ -336,6 +336,7 @@ class PostgreSQLFormatIdentifier {
'_text': PostgreSQLDataType.textArray,
'_float8': PostgreSQLDataType.doubleArray,
'varchar': PostgreSQLDataType.varChar,
+ '_varchar': PostgreSQLDataType.varCharArray,
'_jsonb': PostgreSQLDataType.jsonbArray,
};
diff --git a/lib/src/substituter.dart b/lib/src/substituter.dart
index bf84827d..16f29684 100644
--- a/lib/src/substituter.dart
+++ b/lib/src/substituter.dart
@@ -63,6 +63,8 @@ class PostgreSQLFormat {
return '_float8';
case PostgreSQLDataType.varChar:
return 'varchar';
+ case PostgreSQLDataType.varCharArray:
+ return '_varchar';
case PostgreSQLDataType.jsonbArray:
return '_jsonb';
default:
diff --git a/lib/src/types.dart b/lib/src/types.dart
index 0f7abb05..452a936b 100644
--- a/lib/src/types.dart
+++ b/lib/src/types.dart
@@ -92,6 +92,9 @@ enum PostgreSQLDataType {
/// Must be a [String]
varChar,
+ /// Must be a [List]
+ varCharArray,
+
/// Must be a [List] of encodable objects
jsonbArray,
}
diff --git a/test/decode_test.dart b/test/decode_test.dart
index a6ec4453..e9b89ec8 100644
--- a/test/decode_test.dart
+++ b/test/decode_test.dart
@@ -15,19 +15,20 @@ void main() {
CREATE TEMPORARY TABLE t (
i int, s serial, bi bigint, bs bigserial, bl boolean, si smallint,
t text, f real, d double precision, dt date, ts timestamp, tsz timestamptz, n numeric, j jsonb, ba bytea,
- u uuid, v varchar, p point, jj json, ia _int4, ta _text, da _float8, ja _jsonb)
+ u uuid, v varchar, p point, jj json, ia _int4, ta _text, da _float8, ja _jsonb, va varchar(20)[])
''');
await connection.execute(
- 'INSERT INTO t (i, bi, bl, si, t, f, d, dt, ts, tsz, n, j, ba, u, v, p, jj, ia, ta, da, ja) '
+ 'INSERT INTO t (i, bi, bl, si, t, f, d, dt, ts, tsz, n, j, ba, u, v, p, jj, ia, ta, da, ja, va) '
'VALUES (-2147483648, -9223372036854775808, TRUE, -32768, '
"'string', 10.0, 10.0, '1983-11-06', "
"'1983-11-06 06:00:00.000000', '1983-11-06 06:00:00.000000', "
"'-1234567890.0987654321', "
"'{\"key\":\"value\"}', E'\\\\000', '00000000-0000-0000-0000-000000000000', "
- "'abcdef', '(0.01, 12.34)', '{\"key\": \"value\"}', '{}', '{}', '{}', '{}')");
+ "'abcdef', '(0.01, 12.34)', '{\"key\": \"value\"}', '{}', '{}', '{}', '{}', "
+ "'{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\"}')");
await connection.execute(
- 'INSERT INTO t (i, bi, bl, si, t, f, d, dt, ts, tsz, n, j, ba, u, v, p, jj, ia, ta, da, ja) '
+ 'INSERT INTO t (i, bi, bl, si, t, f, d, dt, ts, tsz, n, j, ba, u, v, p, jj, ia, ta, da, ja, va) '
'VALUES (2147483647, 9223372036854775807, FALSE, 32767, '
"'a significantly longer string to the point where i doubt this actually matters', "
"10.25, 10.125, '2183-11-06', '2183-11-06 00:00:00.111111', "
@@ -35,12 +36,13 @@ void main() {
"'1000000000000000000000000000.0000000000000000000000000001', "
"'[{\"key\":1}]', E'\\\\377', 'FFFFFFFF-ffff-ffff-ffff-ffffffffffff', "
"'01234', '(0.2, 100)', '{}', '{-123, 999}', '{\"a\", \"lorem ipsum\", \"\"}', "
- "'{1, 2, 4.5, 1234.5}', '{1, \"\\\"test\\\"\", \"{\\\"a\\\": \\\"b\\\"}\"}')");
+ "'{1, 2, 4.5, 1234.5}', '{1, \"\\\"test\\\"\", \"{\\\"a\\\": \\\"b\\\"}\"}', "
+ "'{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\"}')");
await connection.execute(
- 'INSERT INTO t (i, bi, bl, si, t, f, d, dt, ts, tsz, n, j, ba, u, v, p, jj, ia, ta, da, ja) '
+ 'INSERT INTO t (i, bi, bl, si, t, f, d, dt, ts, tsz, n, j, ba, u, v, p, jj, ia, ta, da, ja, va) '
'VALUES (null, null, null, null, null, null, null, null, null, null, null, null, null, '
- 'null, null, null, null, null, null, null, null )');
+ 'null, null, null, null, null, null, null, null, null)');
});
tearDown(() async {
await connection.close();
@@ -79,6 +81,8 @@ void main() {
expect(row1[20], equals([]));
expect(row1[21], equals([]));
expect(row1[22], equals([]));
+ expect(row1[23] is List, true);
+ expect(row1[23], equals(['a', 'b', 'c', 'd', 'e', 'f']));
// upper bound row
expect(row2[0], equals(2147483647));
@@ -145,6 +149,7 @@ void main() {
expect(row3[20], isNull);
expect(row3[21], isNull);
expect(row3[22], isNull);
+ expect(row3[23], isNull);
});
test('Fetch/insert empty string', () async {
diff --git a/test/encoding_test.dart b/test/encoding_test.dart
index da3fafdf..529f08ab 100644
--- a/test/encoding_test.dart
+++ b/test/encoding_test.dart
@@ -401,6 +401,19 @@ void main() {
}
});
+ test('varCharArray', () async {
+ await expectInverse([], PostgreSQLDataType.varCharArray);
+ await expectInverse(['', 'foo', 'foo\n'], PostgreSQLDataType.varCharArray);
+ await expectInverse(['foo\nbar;s', '"\'"'], PostgreSQLDataType.varCharArray);
+ try {
+ await conn.query('INSERT INTO t (v) VALUES (@v:_varchar(10))',
+ substitutionValues: {'v': 0});
+ fail('unreachable');
+ } on FormatException catch (e) {
+ expect(e.toString(), contains('Expected: List'));
+ }
+ });
+
test('textArray', () async {
await expectInverse([], PostgreSQLDataType.textArray);
await expectInverse(['', 'foo', 'foo\n'], PostgreSQLDataType.textArray);
diff --git a/test/query_test.dart b/test/query_test.dart
index 504221ca..f5bad919 100644
--- a/test/query_test.dart
+++ b/test/query_test.dart
@@ -14,7 +14,7 @@ void main() {
'bs bigserial, bl boolean, si smallint, '
't text, f real, d double precision, '
'dt date, ts timestamp, tsz timestamptz, j jsonb, u uuid, '
- 'v varchar, p point, jj json, ia _int4, ta _text, da _float8, ja _jsonb)');
+ 'v varchar, p point, jj json, ia _int4, ta _text, da _float8, ja _jsonb, va _varchar(20))');
await connection.execute(
'CREATE TEMPORARY TABLE u (i1 int not null, i2 int not null);');
await connection
@@ -109,7 +109,7 @@ void main() {
test('Query without specifying types', () async {
var result = await connection.query(
- 'INSERT INTO t (i, bi, bl, si, t, f, d, dt, ts, tsz, j, u, v, p, jj, ia, ta, da, ja) values '
+ 'INSERT INTO t (i, bi, bl, si, t, f, d, dt, ts, tsz, j, u, v, p, jj, ia, ta, da, ja, va) values '
'(${PostgreSQLFormat.id('i')},'
'${PostgreSQLFormat.id('bi')},'
'${PostgreSQLFormat.id('bl')},'
@@ -128,8 +128,9 @@ void main() {
'${PostgreSQLFormat.id('ia')},'
'${PostgreSQLFormat.id('ta')},'
'${PostgreSQLFormat.id('da')},'
- '${PostgreSQLFormat.id('ja')}'
- ') returning i,s, bi, bs, bl, si, t, f, d, dt, ts, tsz, j, u, v, p, jj, ia, ta, da, ja',
+ '${PostgreSQLFormat.id('ja')},'
+ '${PostgreSQLFormat.id('va')}'
+ ') returning i,s, bi, bs, bl, si, t, f, d, dt, ts, tsz, j, u, v, p, jj, ia, ta, da, ja, va',
substitutionValues: {
'i': 1,
'bi': 2,
@@ -154,6 +155,7 @@ void main() {
'a"\'\\"',
{'k': 'v"\'\\"'}
],
+ 'va': ['a', 'b', 'c', 'd', 'e', 'f']
});
final expectedRow = [
@@ -181,22 +183,23 @@ void main() {
1,
'a"\'\\"',
{'k': 'v"\'\\"'}
- ]
+ ],
+ ['a', 'b', 'c', 'd', 'e', 'f']
];
- expect(result.columnDescriptions, hasLength(21));
+ expect(result.columnDescriptions, hasLength(22));
expect(result.columnDescriptions.first.tableName, 't');
expect(result.columnDescriptions.first.columnName, 'i');
expect(result.columnDescriptions.last.tableName, 't');
- expect(result.columnDescriptions.last.columnName, 'ja');
+ expect(result.columnDescriptions.last.columnName, 'va');
expect(result, [expectedRow]);
result = await connection.query(
- 'select i,s, bi, bs, bl, si, t, f, d, dt, ts, tsz, j, u, v, p, jj, ia, ta, da, ja from t');
+ 'select i,s, bi, bs, bl, si, t, f, d, dt, ts, tsz, j, u, v, p, jj, ia, ta, da, ja, va from t');
expect(result, [expectedRow]);
});
test('Query by specifying all types', () async {
var result = await connection.query(
- 'INSERT INTO t (i, bi, bl, si, t, f, d, dt, ts, tsz, j, u, v, p, jj, ia, ta, da, ja) values '
+ 'INSERT INTO t (i, bi, bl, si, t, f, d, dt, ts, tsz, j, u, v, p, jj, ia, ta, da, ja, va) values '
'(${PostgreSQLFormat.id('i', type: PostgreSQLDataType.integer)},'
'${PostgreSQLFormat.id('bi', type: PostgreSQLDataType.bigInteger)},'
'${PostgreSQLFormat.id('bl', type: PostgreSQLDataType.boolean)},'
@@ -215,8 +218,9 @@ void main() {
'${PostgreSQLFormat.id('ia', type: PostgreSQLDataType.integerArray)},'
'${PostgreSQLFormat.id('ta', type: PostgreSQLDataType.textArray)},'
'${PostgreSQLFormat.id('da', type: PostgreSQLDataType.doubleArray)},'
- '${PostgreSQLFormat.id('ja', type: PostgreSQLDataType.jsonbArray)}'
- ') returning i,s, bi, bs, bl, si, t, f, d, dt, ts, tsz, j, u, v, p, jj, ia, ta, da, ja',
+ '${PostgreSQLFormat.id('ja', type: PostgreSQLDataType.jsonbArray)},'
+ '${PostgreSQLFormat.id('va', type: PostgreSQLDataType.varCharArray)}'
+ ') returning i,s, bi, bs, bl, si, t, f, d, dt, ts, tsz, j, u, v, p, jj, ia, ta, da, ja, va',
substitutionValues: {
'i': 1,
'bi': 2,
@@ -241,6 +245,7 @@ void main() {
'a',
{'k': 'v'}
],
+ 'va': ['a', 'b', 'c', 'd', 'e', 'f']
});
final expectedRow = [
@@ -269,11 +274,12 @@ void main() {
'a',
{'k': 'v'}
],
+ ['a', 'b', 'c', 'd', 'e', 'f']
];
expect(result, [expectedRow]);
result = await connection.query(
- 'select i,s, bi, bs, bl, si, t, f, d, dt, ts, tsz, j, u, v, p, jj, ia, ta, da, ja from t');
+ 'select i,s, bi, bs, bl, si, t, f, d, dt, ts, tsz, j, u, v, p, jj, ia, ta, da, ja, va from t');
expect(result, [expectedRow]);
});
From b13bac395a3307c003b6336d39fd60148a6bef02 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Istv=C3=A1n=20So=C3=B3s?=
Date: Mon, 6 Jun 2022 09:01:29 +0200
Subject: [PATCH 2/2] Following prior changelog references.
---
CHANGELOG.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e679b276..f31844a9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,9 +1,11 @@
# Changelog
## 2.4.4
-- Added support for varchar arrays.
+
+- Added support for varchar arrays. [#39](https://github.com/isoos/postgresql-dart/pull/39) by [paschalisp](https://github.com/paschalisp).
## 2.4.3
+
- Support for clear text passwords using a boolean parameter in connection as 'allowClearTextPassword' to activate / deactivate the feature. [#20](https://github.com/isoos/postgresql-dart/pull/20).
## 2.4.2