Skip to content

Commit

Permalink
Merge pull request #71 from BreX900/feature/postgres_3
Browse files Browse the repository at this point in the history
Updated the `postgres` package to version `3.0.0`
  • Loading branch information
Kilian Schulte authored Feb 5, 2024
2 parents 04933b7 + 51f3808 commit b30e92f
Show file tree
Hide file tree
Showing 28 changed files with 362 additions and 308 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
- You no longer need to use the `Database` class, you can use `Connection.open` or `Pool` directly.
- `Database` class implements postegres `Session` and `SessionExecutor` classes
- Extension methods for accessing repositories now extend `Session`
- Added the ability to create a Pool for your database
- Updated analyzer dependency to `^6.0.0`
- Updated dart sdk constraints to `>=2.17.0 <4.0.0`

**BREAKING CHANGES**
- Updated the `postgres` package to version `3.0.0`. To visit all the breaking changes see their changelog
- Removed `Database.query` method in favour of `Session.execute` method
- `Action` and `Query` now accept a Session
- Repository methods are no longer wrapped in a transaction
- Removed all fields and methods to execute a transaction in favor of `SessionExecutor.runTx`

# 0.13.1

- Fixed bug with boolean column in migration.
Expand Down
2 changes: 1 addition & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Future<void> main() async {
var db = Database(
port: 2222,
database: 'dart_test',
user: 'postgres',
username: 'postgres',
password: 'postgres',
useSSL: false,
);
Expand Down
28 changes: 14 additions & 14 deletions example/lib/models/account.schema.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

part of 'account.dart';

extension AccountRepositories on Database {
extension AccountRepositories on Session {
AccountRepository get accounts => AccountRepository._(this);
}

Expand All @@ -12,7 +12,7 @@ abstract class AccountRepository
KeyedModelRepositoryInsert<AccountInsertRequest>,
ModelRepositoryUpdate<AccountUpdateRequest>,
ModelRepositoryDelete<int> {
factory AccountRepository._(Database db) = _AccountRepository;
factory AccountRepository._(Session db) = _AccountRepository;

Future<FullAccountView?> queryFullView(int id);
Future<List<FullAccountView>> queryFullViews([QueryParams? params]);
Expand Down Expand Up @@ -64,11 +64,11 @@ class _AccountRepository extends BaseRepository
Future<List<int>> insert(List<AccountInsertRequest> requests) async {
if (requests.isEmpty) return [];
var values = QueryValues();
var rows = await db.query(
'INSERT INTO "accounts" ( "first_name", "last_name", "location", "company_id" )\n'
'VALUES ${requests.map((r) => '( ${values.add(r.firstName)}:text, ${values.add(r.lastName)}:text, ${values.add(LatLngConverter().tryEncode(r.location))}:point, ${values.add(r.companyId)}:text )').join(', ')}\n'
'RETURNING "id"',
values.values,
var rows = await db.execute(
Sql.named('INSERT INTO "accounts" ( "first_name", "last_name", "location", "company_id" )\n'
'VALUES ${requests.map((r) => '( ${values.add(r.firstName)}:text, ${values.add(r.lastName)}:text, ${values.add(LatLngConverter().tryEncode(r.location))}:point, ${values.add(r.companyId)}:text )').join(', ')}\n'
'RETURNING "id"'),
parameters: values.values,
);
var result = rows.map<int>((r) => TextEncoder.i.decode(r.toColumnMap()['id'])).toList();

Expand All @@ -89,13 +89,13 @@ class _AccountRepository extends BaseRepository
Future<void> update(List<AccountUpdateRequest> requests) async {
if (requests.isEmpty) return;
var values = QueryValues();
await db.query(
'UPDATE "accounts"\n'
'SET "first_name" = COALESCE(UPDATED."first_name", "accounts"."first_name"), "last_name" = COALESCE(UPDATED."last_name", "accounts"."last_name"), "location" = COALESCE(UPDATED."location", "accounts"."location"), "company_id" = COALESCE(UPDATED."company_id", "accounts"."company_id")\n'
'FROM ( VALUES ${requests.map((r) => '( ${values.add(r.id)}:int8, ${values.add(r.firstName)}:text, ${values.add(r.lastName)}:text, ${values.add(LatLngConverter().tryEncode(r.location))}:point, ${values.add(r.companyId)}:text )').join(', ')} )\n'
'AS UPDATED("id", "first_name", "last_name", "location", "company_id")\n'
'WHERE "accounts"."id" = UPDATED."id"',
values.values,
await db.execute(
Sql.named('UPDATE "accounts"\n'
'SET "first_name" = COALESCE(UPDATED."first_name", "accounts"."first_name"), "last_name" = COALESCE(UPDATED."last_name", "accounts"."last_name"), "location" = COALESCE(UPDATED."location", "accounts"."location"), "company_id" = COALESCE(UPDATED."company_id", "accounts"."company_id")\n'
'FROM ( VALUES ${requests.map((r) => '( ${values.add(r.id)}:int8::int8, ${values.add(r.firstName)}:text::text, ${values.add(r.lastName)}:text::text, ${values.add(LatLngConverter().tryEncode(r.location))}:point::point, ${values.add(r.companyId)}:text::text )').join(', ')} )\n'
'AS UPDATED("id", "first_name", "last_name", "location", "company_id")\n'
'WHERE "accounts"."id" = UPDATED."id"'),
parameters: values.values,
);
await db.billingAddresses.updateMany(requests.where((r) => r.billingAddress != null).map((r) {
return BillingAddressUpdateRequest(
Expand Down
27 changes: 14 additions & 13 deletions example/lib/models/address.schema.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

part of 'address.dart';

extension AddressRepositories on Database {
extension AddressRepositories on Session {
BillingAddressRepository get billingAddresses => BillingAddressRepository._(this);
}

Expand All @@ -11,7 +11,7 @@ abstract class BillingAddressRepository
ModelRepository,
ModelRepositoryInsert<BillingAddressInsertRequest>,
ModelRepositoryUpdate<BillingAddressUpdateRequest> {
factory BillingAddressRepository._(Database db) = _BillingAddressRepository;
factory BillingAddressRepository._(Session db) = _BillingAddressRepository;

Future<List<BillingAddressView>> queryBillingAddresses([QueryParams? params]);
}
Expand All @@ -32,24 +32,25 @@ class _BillingAddressRepository extends BaseRepository
Future<void> insert(List<BillingAddressInsertRequest> requests) async {
if (requests.isEmpty) return;
var values = QueryValues();
await db.query(
'INSERT INTO "billing_addresses" ( "city", "postcode", "name", "street", "account_id", "company_id" )\n'
'VALUES ${requests.map((r) => '( ${values.add(r.city)}:text, ${values.add(r.postcode)}:text, ${values.add(r.name)}:text, ${values.add(r.street)}:text, ${values.add(r.accountId)}:int8, ${values.add(r.companyId)}:text )').join(', ')}\n',
values.values,
await db.execute(
Sql.named(
'INSERT INTO "billing_addresses" ( "city", "postcode", "name", "street", "account_id", "company_id" )\n'
'VALUES ${requests.map((r) => '( ${values.add(r.city)}:text, ${values.add(r.postcode)}:text, ${values.add(r.name)}:text, ${values.add(r.street)}:text, ${values.add(r.accountId)}:int8, ${values.add(r.companyId)}:text )').join(', ')}\n'),
parameters: values.values,
);
}

@override
Future<void> update(List<BillingAddressUpdateRequest> requests) async {
if (requests.isEmpty) return;
var values = QueryValues();
await db.query(
'UPDATE "billing_addresses"\n'
'SET "city" = COALESCE(UPDATED."city", "billing_addresses"."city"), "postcode" = COALESCE(UPDATED."postcode", "billing_addresses"."postcode"), "name" = COALESCE(UPDATED."name", "billing_addresses"."name"), "street" = COALESCE(UPDATED."street", "billing_addresses"."street")\n'
'FROM ( VALUES ${requests.map((r) => '( ${values.add(r.city)}:text, ${values.add(r.postcode)}:text, ${values.add(r.name)}:text, ${values.add(r.street)}:text, ${values.add(r.accountId)}:int8, ${values.add(r.companyId)}:text )').join(', ')} )\n'
'AS UPDATED("city", "postcode", "name", "street", "account_id", "company_id")\n'
'WHERE "billing_addresses"."account_id" = UPDATED."account_id" AND "billing_addresses"."company_id" = UPDATED."company_id"',
values.values,
await db.execute(
Sql.named('UPDATE "billing_addresses"\n'
'SET "city" = COALESCE(UPDATED."city", "billing_addresses"."city"), "postcode" = COALESCE(UPDATED."postcode", "billing_addresses"."postcode"), "name" = COALESCE(UPDATED."name", "billing_addresses"."name"), "street" = COALESCE(UPDATED."street", "billing_addresses"."street")\n'
'FROM ( VALUES ${requests.map((r) => '( ${values.add(r.city)}:text::text, ${values.add(r.postcode)}:text::text, ${values.add(r.name)}:text::text, ${values.add(r.street)}:text::text, ${values.add(r.accountId)}:int8::int8, ${values.add(r.companyId)}:text::text )').join(', ')} )\n'
'AS UPDATED("city", "postcode", "name", "street", "account_id", "company_id")\n'
'WHERE "billing_addresses"."account_id" = UPDATED."account_id" AND "billing_addresses"."company_id" = UPDATED."company_id"'),
parameters: values.values,
);
}
}
Expand Down
26 changes: 13 additions & 13 deletions example/lib/models/company.schema.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

part of 'company.dart';

extension CompanyRepositories on Database {
extension CompanyRepositories on Session {
CompanyRepository get companies => CompanyRepository._(this);
}

Expand All @@ -12,7 +12,7 @@ abstract class CompanyRepository
ModelRepositoryInsert<CompanyInsertRequest>,
ModelRepositoryUpdate<CompanyUpdateRequest>,
ModelRepositoryDelete<String> {
factory CompanyRepository._(Database db) = _CompanyRepository;
factory CompanyRepository._(Session db) = _CompanyRepository;

Future<FullCompanyView?> queryFullView(String id);
Future<List<FullCompanyView>> queryFullViews([QueryParams? params]);
Expand Down Expand Up @@ -52,10 +52,10 @@ class _CompanyRepository extends BaseRepository
Future<void> insert(List<CompanyInsertRequest> requests) async {
if (requests.isEmpty) return;
var values = QueryValues();
await db.query(
'INSERT INTO "companies" ( "id", "name" )\n'
'VALUES ${requests.map((r) => '( ${values.add(r.id)}:text, ${values.add(r.name)}:text )').join(', ')}\n',
values.values,
await db.execute(
Sql.named('INSERT INTO "companies" ( "id", "name" )\n'
'VALUES ${requests.map((r) => '( ${values.add(r.id)}:text, ${values.add(r.name)}:text )').join(', ')}\n'),
parameters: values.values,
);

await db.billingAddresses.insertMany(requests.expand((r) {
Expand All @@ -73,13 +73,13 @@ class _CompanyRepository extends BaseRepository
Future<void> update(List<CompanyUpdateRequest> requests) async {
if (requests.isEmpty) return;
var values = QueryValues();
await db.query(
'UPDATE "companies"\n'
'SET "name" = COALESCE(UPDATED."name", "companies"."name")\n'
'FROM ( VALUES ${requests.map((r) => '( ${values.add(r.id)}:text, ${values.add(r.name)}:text )').join(', ')} )\n'
'AS UPDATED("id", "name")\n'
'WHERE "companies"."id" = UPDATED."id"',
values.values,
await db.execute(
Sql.named('UPDATE "companies"\n'
'SET "name" = COALESCE(UPDATED."name", "companies"."name")\n'
'FROM ( VALUES ${requests.map((r) => '( ${values.add(r.id)}:text::text, ${values.add(r.name)}:text::text )').join(', ')} )\n'
'AS UPDATED("id", "name")\n'
'WHERE "companies"."id" = UPDATED."id"'),
parameters: values.values,
);
await db.billingAddresses.updateMany(requests.where((r) => r.addresses != null).expand((r) {
return r.addresses!.map((rr) => BillingAddressUpdateRequest(
Expand Down
27 changes: 14 additions & 13 deletions example/lib/models/invoice.schema.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

part of 'invoice.dart';

extension InvoiceRepositories on Database {
extension InvoiceRepositories on Session {
InvoiceRepository get invoices => InvoiceRepository._(this);
}

Expand All @@ -12,7 +12,7 @@ abstract class InvoiceRepository
ModelRepositoryInsert<InvoiceInsertRequest>,
ModelRepositoryUpdate<InvoiceUpdateRequest>,
ModelRepositoryDelete<String> {
factory InvoiceRepository._(Database db) = _InvoiceRepository;
factory InvoiceRepository._(Session db) = _InvoiceRepository;

Future<OwnerInvoiceView?> queryOwnerView(String id);
Future<List<OwnerInvoiceView>> queryOwnerViews([QueryParams? params]);
Expand Down Expand Up @@ -40,24 +40,25 @@ class _InvoiceRepository extends BaseRepository
Future<void> insert(List<InvoiceInsertRequest> requests) async {
if (requests.isEmpty) return;
var values = QueryValues();
await db.query(
'INSERT INTO "invoices" ( "id", "title", "invoice_id", "account_id", "company_id" )\n'
'VALUES ${requests.map((r) => '( ${values.add(r.id)}:text, ${values.add(r.title)}:text, ${values.add(r.invoiceId)}:text, ${values.add(r.accountId)}:int8, ${values.add(r.companyId)}:text )').join(', ')}\n',
values.values,
await db.execute(
Sql.named(
'INSERT INTO "invoices" ( "id", "title", "invoice_id", "account_id", "company_id" )\n'
'VALUES ${requests.map((r) => '( ${values.add(r.id)}:text, ${values.add(r.title)}:text, ${values.add(r.invoiceId)}:text, ${values.add(r.accountId)}:int8, ${values.add(r.companyId)}:text )').join(', ')}\n'),
parameters: values.values,
);
}

@override
Future<void> update(List<InvoiceUpdateRequest> requests) async {
if (requests.isEmpty) return;
var values = QueryValues();
await db.query(
'UPDATE "invoices"\n'
'SET "title" = COALESCE(UPDATED."title", "invoices"."title"), "invoice_id" = COALESCE(UPDATED."invoice_id", "invoices"."invoice_id"), "account_id" = COALESCE(UPDATED."account_id", "invoices"."account_id"), "company_id" = COALESCE(UPDATED."company_id", "invoices"."company_id")\n'
'FROM ( VALUES ${requests.map((r) => '( ${values.add(r.id)}:text, ${values.add(r.title)}:text, ${values.add(r.invoiceId)}:text, ${values.add(r.accountId)}:int8, ${values.add(r.companyId)}:text )').join(', ')} )\n'
'AS UPDATED("id", "title", "invoice_id", "account_id", "company_id")\n'
'WHERE "invoices"."id" = UPDATED."id"',
values.values,
await db.execute(
Sql.named('UPDATE "invoices"\n'
'SET "title" = COALESCE(UPDATED."title", "invoices"."title"), "invoice_id" = COALESCE(UPDATED."invoice_id", "invoices"."invoice_id"), "account_id" = COALESCE(UPDATED."account_id", "invoices"."account_id"), "company_id" = COALESCE(UPDATED."company_id", "invoices"."company_id")\n'
'FROM ( VALUES ${requests.map((r) => '( ${values.add(r.id)}:text::text, ${values.add(r.title)}:text::text, ${values.add(r.invoiceId)}:text::text, ${values.add(r.accountId)}:int8::int8, ${values.add(r.companyId)}:text::text )').join(', ')} )\n'
'AS UPDATED("id", "title", "invoice_id", "account_id", "company_id")\n'
'WHERE "invoices"."id" = UPDATED."id"'),
parameters: values.values,
);
}
}
Expand Down
4 changes: 2 additions & 2 deletions example/lib/models/latlng.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ class LatLngConverter extends TypeConverter<LatLng> {
const LatLngConverter() : super('point');

@override
dynamic encode(LatLng value) => PgPoint(value.latitude, value.longitude);
dynamic encode(LatLng value) => Point(value.latitude, value.longitude);

@override
LatLng decode(dynamic value) {
if (value is PgPoint) {
if (value is Point) {
return LatLng(value.latitude, value.longitude);
} else {
var m = RegExp(r'\((.+),(.+)\)').firstMatch(value.toString());
Expand Down
26 changes: 13 additions & 13 deletions example/lib/models/party.schema.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

part of 'party.dart';

extension PartyRepositories on Database {
extension PartyRepositories on Session {
PartyRepository get parties => PartyRepository._(this);
}

Expand All @@ -12,7 +12,7 @@ abstract class PartyRepository
ModelRepositoryInsert<PartyInsertRequest>,
ModelRepositoryUpdate<PartyUpdateRequest>,
ModelRepositoryDelete<String> {
factory PartyRepository._(Database db) = _PartyRepository;
factory PartyRepository._(Session db) = _PartyRepository;

Future<GuestPartyView?> queryGuestView(String id);
Future<List<GuestPartyView>> queryGuestViews([QueryParams? params]);
Expand Down Expand Up @@ -52,24 +52,24 @@ class _PartyRepository extends BaseRepository
Future<void> insert(List<PartyInsertRequest> requests) async {
if (requests.isEmpty) return;
var values = QueryValues();
await db.query(
'INSERT INTO "parties" ( "id", "name", "sponsor_id", "date" )\n'
'VALUES ${requests.map((r) => '( ${values.add(r.id)}:text, ${values.add(r.name)}:text, ${values.add(r.sponsorId)}:text, ${values.add(r.date)}:int8 )').join(', ')}\n',
values.values,
await db.execute(
Sql.named('INSERT INTO "parties" ( "id", "name", "sponsor_id", "date" )\n'
'VALUES ${requests.map((r) => '( ${values.add(r.id)}:text, ${values.add(r.name)}:text, ${values.add(r.sponsorId)}:text, ${values.add(r.date)}:int8 )').join(', ')}\n'),
parameters: values.values,
);
}

@override
Future<void> update(List<PartyUpdateRequest> requests) async {
if (requests.isEmpty) return;
var values = QueryValues();
await db.query(
'UPDATE "parties"\n'
'SET "name" = COALESCE(UPDATED."name", "parties"."name"), "sponsor_id" = COALESCE(UPDATED."sponsor_id", "parties"."sponsor_id"), "date" = COALESCE(UPDATED."date", "parties"."date")\n'
'FROM ( VALUES ${requests.map((r) => '( ${values.add(r.id)}:text, ${values.add(r.name)}:text, ${values.add(r.sponsorId)}:text, ${values.add(r.date)}:int8 )').join(', ')} )\n'
'AS UPDATED("id", "name", "sponsor_id", "date")\n'
'WHERE "parties"."id" = UPDATED."id"',
values.values,
await db.execute(
Sql.named('UPDATE "parties"\n'
'SET "name" = COALESCE(UPDATED."name", "parties"."name"), "sponsor_id" = COALESCE(UPDATED."sponsor_id", "parties"."sponsor_id"), "date" = COALESCE(UPDATED."date", "parties"."date")\n'
'FROM ( VALUES ${requests.map((r) => '( ${values.add(r.id)}:text::text, ${values.add(r.name)}:text::text, ${values.add(r.sponsorId)}:text::text, ${values.add(r.date)}:int8::int8 )').join(', ')} )\n'
'AS UPDATED("id", "name", "sponsor_id", "date")\n'
'WHERE "parties"."id" = UPDATED."id"'),
parameters: values.values,
);
}
}
Expand Down
24 changes: 15 additions & 9 deletions lib/src/builder/elements/column/column_element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:analyzer/dart/constant/value.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:collection/collection.dart';
import 'package:postgres/postgres.dart';
import 'package:source_gen/source_gen.dart';

import '../../schema.dart';
Expand Down Expand Up @@ -80,21 +81,26 @@ abstract class ColumnElement {
void checkConverter();

late List<ConstantReader> modifiers = () {
if (parameter == null || parameter!.getter == null) return <ConstantReader>[];
final parameter = this.parameter;
final parameterGetter = parameter?.getter;
if (parameter == null || parameterGetter == null) return <ConstantReader>[];

return [
...hiddenInChecker.annotationsOf(parameter!),
...hiddenInChecker.annotationsOf(parameter!.getter!),
...viewedInChecker.annotationsOf(parameter!),
...viewedInChecker.annotationsOf(parameter!.getter!),
...transformedInChecker.annotationsOf(parameter!),
...transformedInChecker.annotationsOf(parameter!.getter!),
...hiddenInChecker.annotationsOf(parameter),
...hiddenInChecker.annotationsOf(parameterGetter),
...viewedInChecker.annotationsOf(parameter),
...viewedInChecker.annotationsOf(parameterGetter),
...transformedInChecker.annotationsOf(parameter),
...transformedInChecker.annotationsOf(parameterGetter),
].map((m) => ConstantReader(m)).toList();
}();

void checkModifiers();
}

final _dateTimeChecker = TypeChecker.fromRuntime(DateTime);
final _pointChecker = TypeChecker.fromRuntime(Point);

String? getSqlType(DartType type) {
if (type.isDartCoreString) {
return 'text';
Expand All @@ -104,9 +110,9 @@ String? getSqlType(DartType type) {
return 'float8';
} else if (type.isDartCoreBool) {
return 'boolean';
} else if (type.element?.name == 'DateTime') {
} else if (_dateTimeChecker.isExactlyType(type)) {
return 'timestamp';
} else if (type.element?.name == 'PgPoint') {
} else if (_pointChecker.isExactlyType(type)) {
return 'point';
} else {
return null;
Expand Down
4 changes: 3 additions & 1 deletion lib/src/builder/elements/table_element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ class TableElement {

late List<FieldElement> allFields = element.fields
.cast<FieldElement>()
.followedBy(element.allSupertypes.expand((t) => t.isDartCoreObject ? [] : t.element.fields))
.followedBy(element.allSupertypes
.expand((t) => t.isDartCoreObject ? <FieldElement>[] : t.element.fields))
.where((e) => !e.hasInitializer)
.toList();

void prepareColumns() {
Expand Down
Loading

0 comments on commit b30e92f

Please sign in to comment.