Skip to content

Commit a949bae

Browse files
committed
add batch support
1 parent 4c3c624 commit a949bae

8 files changed

Lines changed: 309 additions & 25 deletions

flutter/example/lib/main.dart

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ Future<void> setupSentry(AppRunner appRunner, String dsn) async {
5555
options.attachScreenshot = true;
5656
options.screenshotQuality = SentryScreenshotQuality.low;
5757
options.attachViewHierarchy = true;
58-
options.environment = 'dev';
5958
// We can enable Sentry debug logging during development. This is likely
6059
// going to log too much for your app, but can be useful when figuring out
6160
// configuration issues, e.g. finding out why your events are not uploaded.
@@ -410,18 +409,22 @@ class MainScaffold extends StatelessWidget {
410409
bindToScope: true,
411410
);
412411

413-
var db = await openDatabase(inMemoryDatabasePath);
412+
final db = await openDatabase(inMemoryDatabasePath);
413+
// final batch = db.batch();
414414
await db.execute('''
415415
CREATE TABLE Product (
416416
id INTEGER PRIMARY KEY,
417417
title TEXT
418418
)
419419
''');
420+
final dbTitles = <String>[];
420421
for (int i = 1; i <= 20; i++) {
421-
await db.insert('Product', <String, Object?>{'title': 'Product $i'});
422+
final title = 'Product $i';
423+
dbTitles.add(title);
424+
await db.insert('Product', <String, Object?>{'title': title});
422425
}
423426

424-
await db.query('Product');
427+
// await db.query('Product');
425428

426429
await db.transaction((txn) async {
427430
await txn
@@ -430,7 +433,11 @@ class MainScaffold extends StatelessWidget {
430433
where: 'title = ?', whereArgs: ['Product Another one']);
431434
});
432435

433-
await db.delete('Product', where: 'title = ?', whereArgs: ['Product 1']);
436+
// await db.delete('Product', where: 'title = ?', whereArgs: ['Product 1']);
437+
438+
// final batch = db.batch();
439+
// batch.delete('Product', where: 'title = ?', whereArgs: dbTitles);
440+
// await batch.commit();
434441

435442
await db.close();
436443

sqflite/lib/sentry_sqflite.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ library sentry_sqflite;
33
export 'src/sentry_database.dart';
44
export 'src/sentry_sqflite.dart';
55
export 'src/sentry_sqflite_database_factory.dart';
6+
export 'src/sentry_batch.dart';
7+
export 'src/sentry_sqflite_transaction.dart';

sqflite/lib/src/sentry_batch.dart

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
import 'package:meta/meta.dart';
2+
import 'package:sentry/sentry.dart';
3+
import 'package:sqflite/sqflite.dart';
4+
5+
// ignore: implementation_imports, depend_on_referenced_packages
6+
import 'package:sqflite_common/src/sql_builder.dart';
7+
8+
/// A [Batch] wrapper that adds Sentry support.
9+
///
10+
/// ```dart
11+
/// import 'package:sqflite/sqflite.dart';
12+
/// import 'package:sentry_sqflite/sentry_sqflite.dart';
13+
///
14+
/// final database = await openDatabase('path/to/db');
15+
/// final sentryDatabase = SentryDatabase(database);
16+
/// final batch = sentryDatabase.batch();
17+
/// ```
18+
class SentryBatch implements Batch {
19+
final Batch _batch;
20+
final Hub _hub;
21+
22+
// we don't clear the buffer because SqfliteBatch don't either
23+
final _buffer = StringBuffer();
24+
25+
/// ```dart
26+
/// import 'package:sqflite/sqflite.dart';
27+
/// import 'package:sentry_sqflite/sentry_sqflite.dart';
28+
///
29+
/// final database = await openDatabase('path/to/db');
30+
/// final sentryDatabase = SentryDatabase(database);
31+
/// final batch = sentryDatabase.batch();
32+
/// ```
33+
SentryBatch(
34+
this._batch, {
35+
@internal Hub? hub,
36+
}) : _hub = hub ?? HubAdapter();
37+
38+
@override
39+
Future<List<Object?>> apply({bool? noResult, bool? continueOnError}) {
40+
Future<List<Object?>> future() async {
41+
final currentSpan = _hub.getSpan();
42+
43+
final span = currentSpan?.startChild(
44+
'db.sql.execute',
45+
description: _buffer.toString(),
46+
);
47+
48+
try {
49+
final result = await _batch.apply(
50+
noResult: noResult,
51+
continueOnError: continueOnError,
52+
);
53+
54+
span?.status = SpanStatus.ok();
55+
56+
return result;
57+
} catch (exception) {
58+
span?.throwable = exception;
59+
span?.status = SpanStatus.internalError();
60+
61+
rethrow;
62+
} finally {
63+
await span?.finish();
64+
}
65+
}
66+
67+
return future();
68+
}
69+
70+
@override
71+
Future<List<Object?>> commit({
72+
bool? exclusive,
73+
bool? noResult,
74+
bool? continueOnError,
75+
}) {
76+
Future<List<Object?>> future() async {
77+
final currentSpan = _hub.getSpan();
78+
79+
final span = currentSpan?.startChild(
80+
'db.sql.execute',
81+
description: _buffer.toString(),
82+
);
83+
84+
try {
85+
final result = await _batch.commit(
86+
exclusive: exclusive,
87+
noResult: noResult,
88+
continueOnError: continueOnError,
89+
);
90+
91+
span?.status = SpanStatus.ok();
92+
93+
return result;
94+
} catch (exception) {
95+
span?.throwable = exception;
96+
span?.status = SpanStatus.internalError();
97+
98+
rethrow;
99+
} finally {
100+
await span?.finish();
101+
}
102+
}
103+
104+
return future();
105+
}
106+
107+
@override
108+
void delete(String table, {String? where, List<Object?>? whereArgs}) {
109+
final builder =
110+
SqlBuilder.delete(table, where: where, whereArgs: whereArgs);
111+
_buffer.writeln(builder.sql);
112+
113+
_batch.delete(table, where: where, whereArgs: whereArgs);
114+
}
115+
116+
@override
117+
void execute(String sql, [List<Object?>? arguments]) {
118+
_buffer.writeln(sql);
119+
120+
_batch.execute(sql, arguments);
121+
}
122+
123+
@override
124+
void insert(
125+
String table,
126+
Map<String, Object?> values, {
127+
String? nullColumnHack,
128+
ConflictAlgorithm? conflictAlgorithm,
129+
}) {
130+
final builder = SqlBuilder.insert(
131+
table,
132+
values,
133+
nullColumnHack: nullColumnHack,
134+
conflictAlgorithm: conflictAlgorithm,
135+
);
136+
_buffer.writeln(builder.sql);
137+
138+
_batch.insert(
139+
table,
140+
values,
141+
nullColumnHack: nullColumnHack,
142+
conflictAlgorithm: conflictAlgorithm,
143+
);
144+
}
145+
146+
@override
147+
int get length => _batch.length;
148+
149+
@override
150+
void query(
151+
String table, {
152+
bool? distinct,
153+
List<String>? columns,
154+
String? where,
155+
List<Object?>? whereArgs,
156+
String? groupBy,
157+
String? having,
158+
String? orderBy,
159+
int? limit,
160+
int? offset,
161+
}) {
162+
final builder = SqlBuilder.query(
163+
table,
164+
distinct: distinct,
165+
columns: columns,
166+
where: where,
167+
groupBy: groupBy,
168+
having: having,
169+
orderBy: orderBy,
170+
limit: limit,
171+
offset: offset,
172+
whereArgs: whereArgs,
173+
);
174+
_buffer.writeln(builder.sql);
175+
176+
_batch.query(
177+
table,
178+
distinct: distinct,
179+
columns: columns,
180+
where: where,
181+
whereArgs: whereArgs,
182+
groupBy: groupBy,
183+
having: having,
184+
orderBy: orderBy,
185+
limit: limit,
186+
offset: offset,
187+
);
188+
}
189+
190+
@override
191+
void rawDelete(String sql, [List<Object?>? arguments]) {
192+
_buffer.writeln(sql);
193+
194+
_batch.rawDelete(sql, arguments);
195+
}
196+
197+
@override
198+
void rawInsert(String sql, [List<Object?>? arguments]) {
199+
_buffer.writeln(sql);
200+
201+
_batch.rawInsert(sql, arguments);
202+
}
203+
204+
@override
205+
void rawQuery(String sql, [List<Object?>? arguments]) {
206+
_buffer.writeln(sql);
207+
208+
_batch.rawQuery(sql, arguments);
209+
}
210+
211+
@override
212+
void rawUpdate(String sql, [List<Object?>? arguments]) {
213+
_buffer.writeln(sql);
214+
215+
_batch.rawUpdate(sql, arguments);
216+
}
217+
218+
@override
219+
void update(
220+
String table,
221+
Map<String, Object?> values, {
222+
String? where,
223+
List<Object?>? whereArgs,
224+
ConflictAlgorithm? conflictAlgorithm,
225+
}) {
226+
final builder = SqlBuilder.update(
227+
table,
228+
values,
229+
where: where,
230+
whereArgs: whereArgs,
231+
conflictAlgorithm: conflictAlgorithm,
232+
);
233+
_buffer.writeln(builder.sql);
234+
235+
_batch.update(
236+
table,
237+
where: where,
238+
values,
239+
whereArgs: whereArgs,
240+
conflictAlgorithm: conflictAlgorithm,
241+
);
242+
}
243+
}

sqflite/lib/src/sentry_database.dart

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,25 @@ import 'sentry_database_executor.dart';
66
import 'sentry_sqflite_transaction.dart';
77

88
/// A [Database] wrapper that adds Sentry support.
9-
///
9+
///
1010
/// ```dart
1111
/// import 'package:sqflite/sqflite.dart';
1212
/// import 'package:sentry_sqflite/sentry_sqflite.dart';
13-
///
13+
///
1414
/// final database = await openDatabase('path/to/db');
1515
/// final sentryDatabase = SentryDatabase(database);
1616
/// ```
1717
class SentryDatabase extends SentryDatabaseExecutor implements Database {
1818
final Database _database;
1919
final Hub _hub;
2020

21-
// ignore: public_member_api_docs
21+
/// ```dart
22+
/// import 'package:sqflite/sqflite.dart';
23+
/// import 'package:sentry_sqflite/sentry_sqflite.dart';
24+
///
25+
/// final database = await openDatabase('path/to/db');
26+
/// final sentryDatabase = SentryDatabase(database);
27+
/// ```
2228
SentryDatabase(
2329
this._database, {
2430
@internal Hub? hub,
@@ -58,8 +64,11 @@ class SentryDatabase extends SentryDatabaseExecutor implements Database {
5864
}
5965

6066
@override
61-
Future<T> devInvokeSqlMethod<T>(String method, String sql,
62-
[List<Object?>? arguments]) {
67+
Future<T> devInvokeSqlMethod<T>(
68+
String method,
69+
String sql, [
70+
List<Object?>? arguments,
71+
]) {
6372
// ignore: deprecated_member_use
6473
return _database.devInvokeSqlMethod(method, sql);
6574
}
@@ -86,7 +95,7 @@ class SentryDatabase extends SentryDatabaseExecutor implements Database {
8695
final sentryExecutor =
8796
SentryDatabaseExecutor(txn, parentSpan: span, hub: _hub);
8897
final sentrySqfliteTransaction =
89-
SentrySqfliteTransaction(sentryExecutor);
98+
SentrySqfliteTransaction(sentryExecutor, hub: _hub);
9099

91100
return await action(sentrySqfliteTransaction);
92101
}

sqflite/lib/src/sentry_database_executor.dart

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import 'package:sqflite/sqflite.dart';
55
// ignore: implementation_imports, depend_on_referenced_packages
66
import 'package:sqflite_common/src/sql_builder.dart';
77

8+
import 'sentry_batch.dart';
9+
810
@internal
911
// ignore: public_member_api_docs
1012
class SentryDatabaseExecutor implements DatabaseExecutor {
@@ -21,10 +23,7 @@ class SentryDatabaseExecutor implements DatabaseExecutor {
2123
final Hub _hub;
2224

2325
@override
24-
Batch batch() {
25-
// TODO: implement batch, needs a wrapper
26-
return _executor.batch();
27-
}
26+
Batch batch() => SentryBatch(_executor.batch(), hub: _hub);
2827

2928
@override
3029
Database get database => _executor.database;

sqflite/lib/src/sentry_sqflite.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import 'package:sqflite/sqflite.dart';
33
import 'sentry_database.dart';
44

55
/// Opens a database with Sentry support.
6-
///
6+
///
77
/// ```dart
88
/// import 'package:sqflite/sqflite.dart';
99
/// import 'package:sentry_sqflite/sentry_sqflite.dart';
10-
///
10+
///
1111
/// final database = await openDatabaseWithSentry('path/to/db');
1212
/// ```
1313
Future<Database> openDatabaseWithSentry(
@@ -41,11 +41,11 @@ Future<Database> openDatabaseWithSentry(
4141
}
4242

4343
/// Opens a database with Sentry support.
44-
///
44+
///
4545
/// ```dart
4646
/// import 'package:sqflite/sqflite.dart';
4747
/// import 'package:sentry_sqflite/sentry_sqflite.dart';
48-
///
48+
///
4949
/// final database = await openReadOnlyDatabaseWithSentry('path/to/db');
5050
/// ```
5151
Future<Database> openReadOnlyDatabaseWithSentry(String path) {

0 commit comments

Comments
 (0)