Fix nullability in encapsulate

This commit is contained in:
Simon Binder 2021-05-13 11:59:01 +02:00
parent edf74cb860
commit 0d8741a7b4
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
3 changed files with 96 additions and 45 deletions

View File

@ -149,16 +149,16 @@ class TypeGraph {
}
ResolvedType? _encapsulate(Iterable<ResolvedType?> targets) {
return targets
.map((e) => e!.withoutNullabilityInfo)
.fold<ResolvedType?>(null, (previous, element) {
return targets.fold<ResolvedType?>(null, (previous, element) {
if (previous == null) return element;
final previousType = previous.type;
final elementType = element.type;
final elementType = element!.type;
final eitherNullable =
previous.nullable == true || element.nullable == true;
if (previousType == elementType || elementType == BasicType.nullType) {
return previous;
return previous.withNullable(eitherNullable);
}
if (previousType == BasicType.nullType) return element;
@ -168,7 +168,7 @@ class TypeGraph {
// encapsulate two different numeric types to real
if (isIntOrNumeric(previousType) && isIntOrNumeric(elementType)) {
return const ResolvedType(type: BasicType.real);
return ResolvedType(type: BasicType.real, nullable: eitherNullable);
}
// fallback to text if everything else fails

View File

@ -1,39 +0,0 @@
import 'package:sqlparser/sqlparser.dart';
import 'package:test/test.dart';
void main() {
test('regression test for #917', () {
final engine = SqlEngine()
..registerTableFromSql('CREATE TABLE Shops (id INTEGER);')
..registerTableFromSql(
'CREATE TABLE Sales (shop_id INTEGER, date INTEGER, amount REAL);');
final result = engine.analyze('''
SELECT
Shops.id,
SalesYesterday.amount AS amount_yesterday,
SalesToday.amount AS amount_today
FROM Sales AS SalesYesterday,
(
SELECT SalesToday.amount AS amount, SalesToday.shop_id AS shop_id
FROM Sales AS SalesToday
LEFT JOIN Shops ON SalesToday.shop_id = Shops.id
WHERE SalesToday.date = 8
) AS SalesToday
INNER JOIN Shops
ON (SalesYesterday.shop_id = Shops.id)
AND (SalesToday.shop_id = Shops.id)
WHERE SalesYesterday.date = 9
ORDER BY Shops.id;
''');
expect(result.errors, isEmpty);
});
}
extension on SqlEngine {
void registerTableFromSql(String createTable) {
final stmt = parse(createTable).rootNode as CreateTableStatement;
registerTable(schemaReader.read(stmt));
}
}

View File

@ -0,0 +1,90 @@
import 'package:sqlparser/sqlparser.dart';
import 'package:test/test.dart';
void main() {
test('regression test for #917', () {
// Test for https://github.com/simolus3/moor/issues/917
final engine = SqlEngine()
..registerTableFromSql('CREATE TABLE Shops (id INTEGER);')
..registerTableFromSql(
'CREATE TABLE Sales (shop_id INTEGER, date INTEGER, amount REAL);');
final result = engine.analyze('''
SELECT
Shops.id,
SalesYesterday.amount AS amount_yesterday,
SalesToday.amount AS amount_today
FROM Sales AS SalesYesterday,
(
SELECT SalesToday.amount AS amount, SalesToday.shop_id AS shop_id
FROM Sales AS SalesToday
LEFT JOIN Shops ON SalesToday.shop_id = Shops.id
WHERE SalesToday.date = 8
) AS SalesToday
INNER JOIN Shops
ON (SalesYesterday.shop_id = Shops.id)
AND (SalesToday.shop_id = Shops.id)
WHERE SalesYesterday.date = 9
ORDER BY Shops.id;
''');
expect(result.errors, isEmpty);
});
test('regression test for #1188', () {
// Test for https://github.com/simolus3/moor/issues/1188
final engine = SqlEngine(EngineOptions(useMoorExtensions: true))
..registerTableFromSql('''
CREATE TABLE IF NOT EXISTS "employees" (
"id" INTEGER NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL UNIQUE,
"manager_id" INTEGER
);
''')
..registerTableFromSql('''
CREATE TABLE IF NOT EXISTS "employee_notes" (
"employee_id" INTEGER NOT NULL PRIMARY KEY,
"note" TEXT
);
''');
final result = engine.analyze('''
WITH RECURSIVE
employeeHierarchy(id, name, manager_id) AS (
SELECT id,
name,
manager_id
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT e.id,
e.name,
e.manager_id
FROM employees e
JOIN employeeHierarchy ON e.manager_id = employeeHierarchy.id
)
SELECT e.id,
e.name,
e.manager_id,
n.note
FROM employeeHierarchy e
LEFT OUTER JOIN
employee_notes n ON e.id = n.employee_id
ORDER BY e.id;
''');
final select = result.root as SelectStatement;
final columns = select.resolvedColumns!;
expect(columns.map((e) => e.name), ['id', 'name', 'manager_id', 'note']);
expect(columns.map((e) => result.typeOf(e).nullable),
[false, false, true, true]);
});
}
extension on SqlEngine {
void registerTableFromSql(String createTable) {
final stmt = parse(createTable).rootNode as CreateTableStatement;
registerTable(schemaReader.read(stmt));
}
}