Brick 3 removes the abstract packages since Sqflite has abstracted its Flutter dependency to a "common" API.
brick_offline_first_with_graphql_abstract
, brick_offline_first_with_rest_abstract
, brick_sqlite_abstract
, and brick_offline_first_abstract
will remain on pub.dev since publishing is forever. While this change is internal, parent packages no longer export the contents of child packages. Some adjustments may need to be made.
- Primary package files are renamed in line with
pub.dev
standards.for FILE in $(find "lib" -type f -name "*.dart"); do sed -i '' 's/package:brick_offline_first\/offline_first.dart/package:brick_offline_first\/brick_offline_first.dart/g' $FILE sed -i '' 's/package:brick_offline_first_with_rest\/offline_first_with_rest.dart/package:brick_offline_first_with_rest\/brick_offline_first_with_rest.dart/g' $FILE sed -i '' 's/package:brick_offline_first_with_graphql\/offline_first_with_graphql.dart/package:brick_offline_first_with_graphql\/brick_offline_first_with_graphql.dart/g' $FILE sed -i '' 's/package:brick_rest\/rest.dart/package:brick_rest\/brick_rest.dart/g' $FILE sed -i '' 's/package:brick_sqlite\/sqlite.dart/package:brick_sqlite\/brick_sqlite.dart/g' $FILE sed -i '' 's/package:brick_graphql\/graphql.dart/package:brick_graphql\/brick_graphql.dart/g' $FILE done
brick_offline_first/offline_first.dart
is nowbrick_offline_first/brick_offline_first.dart
brick_offline_first_with_rest/offline_first_with_rest.dart
is nowbrick_offline_first_with_rest/brick_offline_first_with_rest.dart
brick_offline_first_with_graphql/brick_offline_first_with_graphql.dart
is nowbrick_offline_first_with_graphql/brick_offline_first_with_graphql.dart
brick_graphql/graphql.dart
is nowbrick_rest/brick_graphql.dart
brick_rest/rest.dart
is nowbrick_rest/brick_rest.dart
brick_sqlite/sqlite.dart
is nowbrick_sqlite/brick_sqlite.dart
brick_sqlite_abstract/db.dart
is nowbrick_sqlite/db.dart
.brick_sqlite_abstract/sqlite_model.dart
andbrick_sqlite_abstract/annotations.dart
are now exported bybrick_sqlite/brick_sqlite.dart
for FILE in $(find "lib" -type f -name "*.dart"); do sed -i '' 's/package:brick_sqlite_abstract\/annotations.dart/package:brick_sqlite\/brick_sqlite.dart/g' $FILE sed -i '' 's/package:brick_sqlite_abstract\/sqlite_model.dart/package:brick_sqlite\/brick_sqlite.dart/g' $FILE sed -i '' 's/package:brick_sqlite_abstract\/db.dart/package:brick_sqlite\/db.dart/g' $FILE done
RestAdapter.firstWhereOrNull
andGraphqlAdapter.firstWhereOrNull
have been removed. Insteadimport 'package:collection/collection.dart';
and use the bundledIterable
extension.firstWhereOrNull
RestAdapter.enumValuesByName
andGraphqlAdapter.enumValuesByName
have been removed. Instead use Dart 2.15's built-in<enum>.values.byName
- The minimum Dart version has been increased to 2.18
providerArgs
in Brick Rest have changed:'topLevelKey'
and'headers'
and'supplementalTopLevelData'
have been removed (use'request'
) and'request'
now accepts aRestRequest
instead of the HTTP method string.providerArgs
in Brick Graphql have changed:'document'
and'variables'
have been removed. Instead, use'operation'
.analyzer
is now>= 5
FieldRename
,Graphql
GraphqlProvider
, andGraphqlSerializable
are no longer exported byoffline_first_with_graphql.dart
. Instead, import these file frompackage:brick_graphql/brick_graphql.dart
FieldRename
,Rest
,RestProvider
, andRestSerializable
are no longer exported byoffline_first_with_rest.dart
. Instead, import these file frompackage:brick_rest/brick_rest.dart
OfflineFirstWithRestRepository#reattemptForStatusCodes
has been removed from instance-level access. The constructor argument forwards to theRestOfflineQueueClient
, where it can be accessed if needed.OfflineFirstWithRestRepository#throwTunnerNotFoundExceptions
has been removed. This value was duplicated fromofflineQueueManager
; the queue manager is where the property exclusively lives now.
- Listen for SQLite changes via
OfflineFirstWithRestRepository#subscribe
This breaking change migration is less automatable. The script below is a best attempt and should be manually confirmed after running.
for FILE in $(find "lib" -type f -name "*.dart"); do
# `sed` regex capture may work for you; it didn't on Mac for me
# sed -i '' "s/\'document\': (.*)/\'operation\': GraphqlOperation\(document: \1\) \/\/ TODO verify migration to GraphqlOperation /g" $FILE
perl -0777 -i -pe "s/'document': (.*)/'operation': GraphqlOperation\(document: \1\) \/\/ TODO verify migration to GraphqlOperation /igs" $FILE
# sed -i '' "s/\'variables\': (.*)/\'operation\': GraphqlOperation\(variables: \1\) \/\/ TODO verify migration to GraphqlOperation /g" $FILE
perl -0777 -i -pe "s/'variables': (.*)/'operation': GraphqlOperation\(variables: \1\) \/\/ TODO verify migration to GraphqlOperation /igs" $FILE
done
This has been consolidated to 'operation'
. For example: providerArgs: { 'operation': GraphqlOperation(document: r'''mutation UpdateUser(id: ....)''')}
.
This has been consolidated to 'operation'
. For example: providerArgs: { 'operation': GraphqlOperation(variables: {'id': '1'}) }
.
This breaking change migration is less automatable. The script below is a best attempt and should be manually confirmed after running.
for FILE in $(find "lib" -type f -name "*.dart"); do
# `sed` regex capture may work for you; it didn't on Mac for me
# sed -i '' "s/\'request\': (.*)/\'request\': RestRequest\(method: \1\) \/\/ TODO verify migration to RestRequest /g" $FILE
perl -0777 -i -pe "s/'request': (.*)/'request': RestRequest\(method: \1\) \/\/ TODO verify migration to RestRequest /igs" $FILE
# sed -i '' "s/\'headers\': (.*)/\'request\': RestRequest\(headers: \1\) \/\/ TODO verify migration to RestRequest /g" $FILE
perl -0777 -i -pe "s/'headers': (.*)/'request': RestRequest\(headers: \1\) \/\/ TODO verify migration to RestRequest /igs" $FILE
# sed -i '' "s/\'topLevelKey\': (.*)/\'request\': RestRequest\(topLevelKey: \1\) \/\/ TODO verify migration to RestRequest /g" $FILE
perl -0777 -i -pe "s/'topLevelKey': (.*)/'request': RestRequest\(topLevelKey: \1\) \/\/ TODO verify migration to RestRequest /igs" $FILE
# sed -i '' "s/\'supplementalTopLevelData\': (.*)/\'request\': RestRequest\(supplementalTopLevelData: \1\) \/\/ TODO verify migration to RestRequest /g" $FILE
perl -0777 -i -pe "s/'supplementalTopLevelData': (.*)/'request': RestRequest\(supplementalTopLevelData: \1\) \/\/ TODO verify migration to RestRequest /igs" $FILE
done
This key now accepts a RestRequest
class instead of an HTTP method name.
This has been consolidated to 'request'
. For example: providerArgs: { 'request': RestRequest(headers: {'Authorization': 'Bearer'})}
.
This has been consolidated to 'request'
. For example: providerArgs: { 'request': RestRequest(topLevelKey: 'myKey' )}
.
This has been consolidated to 'request'
. For example: providerArgs: { 'request': RestRequest(supplementalTopLevelData: {'myKey': {'myData': 1}}) }
.
RestSerializable
'sfromKey
andtoKey
have been consolidated toRestRequest(topLevelKey:)
RestSerializable(endpoint:)
has been replaced in this release byRestSerializable(requestTransformer:)
. It will be painful to upgrade though with good reason.
- Strongly-typed classes.
endpoint
was a string, which removed analysis in IDEs, permitting errors to escape during runtime. With endpoints as classes,Query
andinstance
objects will receive type hinting. - Fine control over REST requests. Define on a request-level basis what key to pull from or push to. Declare specific HTTP methods like
PATCH
in a class that manages request instead of in distributedproviderArgs
. - Future-proof development. Enhancing REST's configuration will be on a class object instead of in untyped string keys on
providerArgs
. The REST interface is consolidated to this subclass.
Since all APIs are different, and endpoint
used stringified code, the migration cannot be scripted for all users. Instead, examples are provided below to illustrate how to refactor from Brick 2's endpoint
to Brick 3's requestTransformer
. Some examples:
// BEFORE
@ConnectOfflineFirstWithRest(
restConfig: RestSerializable(
endpoint: '"/users";'
fromKey: 'users',
)
)
// AFTER
class UserRequestTransformer extends RestRequestTransformer {
final get = const RestRequest(url: '/users', topLevelKey: 'users');
const UserRequestTransformer(Query? query, RestModel? instance) : super(query, instance);
}
@ConnectOfflineFirstWithRest(
restConfig: RestSerializable(
requestTransformer: UserRequestTransformer.new,
)
)
Some cases are more complex:
// BEFORE
@ConnectOfflineFirstWithRest(
restConfig: RestSerializable(
endpoint: r'''{
if (query?.action == QueryAction.delete) return "/users/${instance.id}";
if (query?.action == QueryAction.get &&
query?.providerArgs.isNotEmpty &&
query?.providerArgs['limit'] != null) {
return "/users?limit=${query.providerArgs['limit']}";
}
return "/users";
}''';
)
)
// AFTER
class UserRequestTransformer extends RestRequestTransformer {
RestRequest? get get {
if (query?.providerArgs.isNotEmpty && query.providerArgs['limit'] != null) {
return RestRequest(url: "/users?limit=${query.providerArgs['limit']}");
}
const RestRequest(url: '/users');
}
final delete = RestRequest(url: '/users/${instance.id}');
const UserRequestTransformer(Query? query, RestModel? instance) : super(query, instance);
}
@ConnectOfflineFirstWithRest(
restConfig: RestSerializable(
requestTransformer: UserRequestTransformer.new,
)
)
💡 For ease of illustration, the code is provided as if the transformer and model logic live in the same file. It's strongly recommended to include the request transformer logic in its own, colocated file (such as user.model.request.dart
).
Brick 2 focuses on Brick problems encountered at scale. While the primary refactor was the abstraction of domain-specific code from generalized domains, this major release also includes a new GraphQL domain, resolution of community pain points, and a few neat tricks.
- Brick no longer expects
lib/app
; it now expectslib/brick
.mv -r lib/app lib/brick
- Models are no longer discovered in
lib/app/models
; they are now discovered via*.model.dart
. They can live in any directory withinlib
and have any prefix. (#38)for FILENAME in lib/brick/models/*; do mv $FILENAME "${FILENAME/dart/model.dart}"; done
brick_offline_first
is now, fundamentally,brick_offline_first_with_rest
.brick_offline_first
now serves as an abstract bedrock for offline domains.sed -i '' 's/brick_offline_first:/brick_offline_first_with_rest:/g' pubspec.yaml for FILE in $(find "lib" -type f -name "*.dart"); do sed -i '' 's/package:brick_offline_first/package:brick_offline_first_with_rest/g' $FILE; done
brick_offline_first_abstract
is nowbrick_offline_first_with_rest_abstract
sed -i '' 's/brick_offline_first_abstract:/brick_offline_first_with_rest_abstract:/g' pubspec.yaml for FILE in $(find "lib" -type f -name "*.dart"); do sed -i '' 's/package:brick_offline_first_abstract/package:brick_offline_first_with_rest_abstract/g' $FILE; done
rest
properties have been removed fromOfflineFirstException
. UseOfflineFirstWithRestException
instead frombrick_offline_first_with_rest
.OfflineFirstRepository#get(requireRemote:
andOfflineFirstRepository#getBatched(requireRemote:
has been removed. Instead, usepolicy: OfflineFirstGetPolicy.alwaysHydrate
OfflineFirstRepository#get(hydrateUnexisting:
has been removed. Instead, usepolicy: OfflineFirstGetPolicy.awaitRemoteWhenNoneExist
(this is the default).OfflineFirstRepository#get(alwaysHydrate:
has been removed. Instead, usepolicy: OfflineFirstGetPolicy.alwaysHydrate
.
- Utilize
OfflineFirstDeletePolicy
,OfflineFirstGetPolicy
, andOfflineFirstUpsertPolicy
to override default behavior. Specific policies will throw an exception when the remote responds with an error (and throw that error) or skip the queue. Existing default behavior is maintained. OfflineFirstRepository#delete
now supports requiring a successful remote withOfflineFirstDeletePolicy.requireRemote
. If the app is offline, normally handled exceptions (ClientException
andSocketException
) arerethrow
n. (#182)OfflineFirstRepository#upsert
now supports requiring a successful remote withOfflineFirstUpsertPolicy.requireRemote
. If the app is offline, normally handled exceptions (ClientException
andSocketException
) arerethrow
n.
brick_graphql
. TheGraphqlProvider
interfaces with a GraphQL backend. It uses gql's Link system to integrate with other community-supported functionality. That, and all your variables are autogenerated on every request.brick_graphql_generators
. The perfect companion tobrick_graphql
, this thin layer aroundbrick_rest_generators
battle-tested core compiles adapters for the GraphQL domain.brick_json_generators
. The experienced core separated frombrick_rest_generators
permits more code reuse and package creation for JSON-serving remote providers.brick_offline_first_build
. Abstracted from the experienced core ofbrick_offline_first_with_rest_build
, these helper generators and utils simplify adding offline capabilites to a domain.brick_offline_first_with_graphql
. Utilize the GraphQL provider with SQLite and Memory cache. This is a near mirror ofbrick_offline_first_with_rest
, save for a few exceptions. First, the OfflineQueueLink must be inserted in the appropriate position in your client's Link chain. Second,OfflineFirstWithGraphqlRepository#subscribe
permits streaming updates, including notifications after local providers are updated.brick_offline_first_with_graphql_abstract
. Annotations for the GraphQL domain without including Flutter.brick_offline_first_with_graphql_build
. The culmination ofbrick_graphql_generators
andbrick_offline_first_build
.
- Because
required
is now a reserved Dart keyword,required
inWherePhrase
,WhereCondition
,And
,Or
, andWhere
has been renamed toisRequired
. - Field types in models
Set<Future<OfflineFirstModel>>
,List<Future<OfflineFirstModel>>
, andFuture<OfflineFirstModel>
are no longer supported. Instead, useSet<OfflineFirstModel>
,List<OfflineFirstModel>
, andOfflineFirstModel
(the adapters willawait
each). StubOfflineFirstWithRest
is functionally changed. SQLiteFFI has satisfied much of the original stubbing required for this class, and http's testing.dart library is sufficient to not require Mockito. Therefore,verify
calls will no longer be effective in testing on the client. Instead, passStubOfflineFirstWithRest.client
to yourRestProvider#client
with the response values.StubOfflineFirstWithRestModel
has been removed. Please review Offline First Testing for implementation examples.
brick_offline_first
: Priority for the next job to process from the queue - when processing requests in serial - has changed from'$HTTP_JOBS_CREATED_AT_COLUMN ASC, $HTTP_JOBS_ATTEMPTS_COLUMN DESC, $HTTP_JOBS_UPDATED_AT ASC'
to'$HTTP_JOBS_CREATED_AT_COLUMN ASC'
; this uses the job column introduced in 0.0.7 (26 May 2020) and will not affect any implementations using 0.0.7 or higher.brick_offline_first
:RequestSqliteCache
no longer queries cached requests based on headers; requests are rediscovered based on their encoding, URL, request method, and body. Rehydrated (reattempted) requests will be hydrated with headers from the original request.- Every package is null safe. There is one outstanding dependency -
build_config
- that needs to be migrated, so the generators are not technically "null safe". However, these are dev dependencies andbuild_config
isn't imported into Dart code, so upgrading it will be changing numbers.