Skip to content

Commit eff8bd0

Browse files
committed
draft impl
1 parent 30c1193 commit eff8bd0

17 files changed

+3979
-36
lines changed

dart/lib/src/sentry_trace_origins.dart

+1
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ class SentryTraceOrigins {
1818
'auto.db.sqflite.database_executor';
1919
static const autoDbSqfliteDatabaseFactory =
2020
'auto.db.sqflite.database_factory';
21+
static const autoDbDriftDatabaseExecutor = 'auto.db.drift.database.executor';
2122
}

drift/.gitignore

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Omit committing pubspec.lock for library packages; see
2+
# https://dart.dev/guides/libraries/private-files#pubspeclock.
3+
pubspec.lock
4+
5+
# Flutter/Dart/Pub related
6+
**/doc/api/
7+
**/ios/Flutter/.last_build_id
8+
.dart_tool/
9+
.flutter-plugins
10+
.flutter-plugins-dependencies
11+
.packages
12+
.pub-cache/
13+
.pub/
14+
/build/

drift/CHANGELOG.md

+1,596
Large diffs are not rendered by default.

drift/LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2019 Sentry
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

drift/analysis_options.yaml

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
include: package:lints/recommended.yaml
2+
3+
analyzer:
4+
language:
5+
strict-casts: true
6+
strict-inference: true
7+
strict-raw-types: true
8+
errors:
9+
# treat missing required parameters as a warning (not a hint)
10+
missing_required_param: error
11+
# treat missing returns as a warning (not a hint)
12+
missing_return: error
13+
# allow having TODOs in the code
14+
todo: ignore
15+
# allow self-reference to deprecated members (we do this because otherwise we have
16+
# to annotate every member in every test, assert, etc, when we deprecate something)
17+
deprecated_member_use_from_same_package: warning
18+
# ignore sentry/path on pubspec as we change it on deployment
19+
invalid_dependency: ignore
20+
unnecessary_import: ignore
21+
exclude:
22+
- example/**
23+
24+
linter:
25+
rules:
26+
- prefer_final_locals
27+
- public_member_api_docs
28+
- prefer_single_quotes
29+
- prefer_relative_imports
30+
- unnecessary_brace_in_string_interps
31+
- implementation_imports
32+
- require_trailing_commas
33+
- unawaited_futures

drift/dartdoc_options.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
dartdoc:
2+
errors:
3+
- unresolved-doc-reference

drift/lib/sentry_drift.dart

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
library sentry_drift;
+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import 'dart:async';
2+
3+
import 'package:drift/backends.dart';
4+
import 'package:meta/meta.dart';
5+
import 'package:sentry/sentry.dart';
6+
import 'sentry_span_helper.dart';
7+
8+
/// Signature of a function that opens a database connection when instructed to.
9+
typedef DatabaseOpener = FutureOr<QueryExecutor> Function();
10+
11+
/// Sentry Drift Database Executor based on [LazyDatabase].
12+
///
13+
/// A special database executor that delegates work to another [QueryExecutor].
14+
/// The other executor is lazily opened by a [DatabaseOpener].
15+
class SentryDriftDatabase extends QueryExecutor {
16+
final Hub _hub;
17+
final _spanHelper = SentrySpanHelper(
18+
// ignore: invalid_use_of_internal_member
19+
SentryTraceOrigins.autoDbDriftDatabaseExecutor,
20+
);
21+
22+
String? dbName = 'people-drift-impl';
23+
24+
@internal
25+
// ignore: public_member_api_docs
26+
static const dbNameKey = 'db.name';
27+
28+
@internal
29+
// ignore: public_member_api_docs
30+
static const dbOp = 'db';
31+
32+
@internal
33+
// ignore: public_member_api_docs
34+
static const dbSystemKey = 'db.system';
35+
36+
@internal
37+
// ignore: public_member_api_docs
38+
static const dbSystem = 'sqlite';
39+
40+
/// Underlying executor
41+
late final QueryExecutor _delegate;
42+
43+
bool _delegateAvailable = false;
44+
final SqlDialect _dialect;
45+
46+
Completer<void>? _openDelegate;
47+
48+
@override
49+
SqlDialect get dialect {
50+
// Drift reads dialect before database opened, so we must know in advance
51+
if (_delegateAvailable && _dialect != _delegate.dialect) {
52+
throw Exception('LazyDatabase created with $_dialect, but underlying '
53+
'database is ${_delegate.dialect}.');
54+
}
55+
return _dialect;
56+
}
57+
58+
/// The function that will open the database when this [SentryDriftDatabase] gets
59+
/// opened for the first time.
60+
final DatabaseOpener opener;
61+
62+
/// Declares a [SentryDriftDatabase] that will run [opener] when the database is
63+
/// first requested to be opened. You must specify the same [dialect] as the
64+
/// underlying database has
65+
SentryDriftDatabase(
66+
this.opener, {
67+
SqlDialect dialect = SqlDialect.sqlite,
68+
@internal Hub? hub,
69+
}) : _dialect = dialect,
70+
_hub = hub ?? HubAdapter() {
71+
_spanHelper.setHub(_hub);
72+
}
73+
74+
Future<void> _awaitOpened() {
75+
if (_delegateAvailable) {
76+
return Future.value();
77+
} else if (_openDelegate != null) {
78+
return _openDelegate!.future;
79+
} else {
80+
final delegate = _openDelegate = Completer();
81+
Future.sync(opener).then((database) {
82+
_delegate = database;
83+
_delegateAvailable = true;
84+
delegate.complete();
85+
}, onError: delegate.completeError);
86+
return delegate.future;
87+
}
88+
}
89+
90+
@override
91+
92+
@override
93+
TransactionExecutor beginTransaction() {
94+
final a = _delegate.beginTransaction();
95+
print(a.toString());
96+
return _delegate.beginTransaction();
97+
}
98+
99+
@override
100+
Future<bool> ensureOpen(QueryExecutorUser user) {
101+
return _awaitOpened().then((_) => _delegate.ensureOpen(user));
102+
}
103+
104+
@override
105+
Future<void> runBatched(BatchedStatements statements) {
106+
return _delegate.runBatched(statements);
107+
}
108+
109+
@override
110+
Future<void> runCustom(String statement, [List<Object?>? args]) {
111+
return _spanHelper.asyncWrapInSpan('custom', () async {
112+
return await _delegate.runCustom(statement, args);
113+
}, dbName: dbName);
114+
}
115+
116+
@override
117+
Future<int> runDelete(String statement, List<Object?> args) {
118+
return _spanHelper.asyncWrapInSpan('delete', () async {
119+
return await _delegate.runDelete(statement, args);
120+
}, dbName: dbName);
121+
}
122+
123+
@override
124+
Future<int> runInsert(String statement, List<Object?> args) {
125+
return _spanHelper.asyncWrapInSpan('insert', () async {
126+
return await _delegate.runInsert(statement, args);
127+
}, dbName: dbName);
128+
}
129+
130+
@override
131+
Future<List<Map<String, Object?>>> runSelect(
132+
String statement, List<Object?> args) {
133+
return _spanHelper.asyncWrapInSpan('select', () async {
134+
return await _delegate.runSelect(statement, args);
135+
}, dbName: dbName);
136+
}
137+
138+
@override
139+
Future<int> runUpdate(String statement, List<Object?> args) {
140+
return _spanHelper.asyncWrapInSpan('update', () async {
141+
return await _delegate.runUpdate(statement, args);
142+
}, dbName: dbName);
143+
}
144+
145+
@override
146+
Future<void> close() {
147+
return _spanHelper.asyncWrapInSpan('close', () async {
148+
if (_delegateAvailable) {
149+
return _delegate.close();
150+
} else {
151+
return Future.value();
152+
}
153+
}, dbName: dbName);
154+
}
155+
}

drift/lib/src/sentry_span_helper.dart

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import 'package:meta/meta.dart';
2+
3+
import 'package:sentry/sentry.dart';
4+
5+
import 'sentry_drift_database.dart';
6+
7+
/// @nodoc
8+
@internal
9+
class SentrySpanHelper {
10+
/// @nodoc
11+
Hub _hub = HubAdapter();
12+
13+
/// @nodoc
14+
final String _origin;
15+
16+
/// @nodoc
17+
SentrySpanHelper(this._origin);
18+
19+
/// @nodoc
20+
void setHub(Hub hub) {
21+
_hub = hub;
22+
}
23+
24+
/// @nodoc
25+
@internal
26+
Future<T> asyncWrapInSpan<T>(
27+
String description,
28+
Future<T> Function() execute, {
29+
String? dbName,
30+
}) async {
31+
final currentSpan = _hub.getSpan();
32+
final span = currentSpan?.startChild(
33+
SentryDriftDatabase.dbOp,
34+
description: description,
35+
);
36+
37+
// ignore: invalid_use_of_internal_member
38+
span?.origin = _origin;
39+
40+
span?.setData(SentryDriftDatabase.dbSystemKey, SentryDriftDatabase.dbSystem);
41+
42+
if (dbName != null) {
43+
span?.setData(SentryDriftDatabase.dbNameKey, dbName);
44+
}
45+
46+
try {
47+
final result = await execute();
48+
49+
span?.status = SpanStatus.ok();
50+
51+
return result;
52+
} catch (exception) {
53+
span?.throwable = exception;
54+
span?.status = SpanStatus.internalError();
55+
rethrow;
56+
} finally {
57+
await span?.finish();
58+
}
59+
}
60+
}

drift/pubspec.yaml

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: sentry_drift
2+
description: An integration which adds support for performance tracing for the drift package.
3+
version: 7.12.0
4+
homepage: https://docs.sentry.io/platforms/flutter/
5+
repository: https://github.com/getsentry/sentry-dart
6+
issue_tracker: https://github.com/getsentry/sentry-dart/issues
7+
8+
environment:
9+
sdk: '>=2.17.0 <4.0.0'
10+
11+
dependencies:
12+
sentry: 7.12.0
13+
meta: ^1.3.0
14+
15+
drift: ^2.13.0
16+
sqlite3_flutter_libs: ^0.5.0
17+
path_provider: ^2.0.0
18+
path: ^1.8.3
19+
20+
dev_dependencies:
21+
lints: ^3.0.0
22+
test: ^1.21.0
23+
coverage: ^1.3.0
24+
mockito: ^5.1.0
25+
build_runner: ^2.4.6
26+
drift_dev: ^2.13.0
27+
yaml: ^3.1.0 # needed for version match (code and pubspec)

drift/pubspec_overrides.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
dependency_overrides:
2+
sentry:
3+
path: ../dart

drift/test/mocks/mocks.dart

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import 'package:mockito/annotations.dart';
2+
import 'package:sentry/sentry.dart';
3+
4+
import '../test_database.dart';
5+
6+
@GenerateMocks([
7+
Hub,
8+
AppDatabase,
9+
TodoItems,
10+
])
11+
void main() {}

0 commit comments

Comments
 (0)