diff --git a/.github/recipe.yaml b/.github/recipe.yaml
index e173687..3e63859 100644
--- a/.github/recipe.yaml
+++ b/.github/recipe.yaml
@@ -1,5 +1,5 @@
plugins:
firebase_core: ["tv-7.0"]
- firebase_database: []
+ firebase_database: ["tv-7.0"]
firebase_storage: []
cloud_functions: []
diff --git a/packages/firebase_database/.clang-format b/packages/firebase_database/.clang-format
new file mode 100644
index 0000000..5ab0945
--- /dev/null
+++ b/packages/firebase_database/.clang-format
@@ -0,0 +1,3 @@
+---
+BasedOnStyle: Google
+---
diff --git a/packages/firebase_database/.gitignore b/packages/firebase_database/.gitignore
new file mode 100644
index 0000000..96486fd
--- /dev/null
+++ b/packages/firebase_database/.gitignore
@@ -0,0 +1,30 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
+/pubspec.lock
+**/doc/api/
+.dart_tool/
+.packages
+build/
diff --git a/packages/firebase_database/CHANGELOG.md b/packages/firebase_database/CHANGELOG.md
new file mode 100644
index 0000000..6073234
--- /dev/null
+++ b/packages/firebase_database/CHANGELOG.md
@@ -0,0 +1,3 @@
+## 0.1.0
+
+* Initial release.
diff --git a/packages/firebase_database/LICENSE b/packages/firebase_database/LICENSE
new file mode 100644
index 0000000..b507088
--- /dev/null
+++ b/packages/firebase_database/LICENSE
@@ -0,0 +1,45 @@
+```
+Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+```
+
+```
+Copyright 2017 The Chromium Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+```
diff --git a/packages/firebase_database/README.md b/packages/firebase_database/README.md
new file mode 100644
index 0000000..fe4a284
--- /dev/null
+++ b/packages/firebase_database/README.md
@@ -0,0 +1,44 @@
+# firebase_database_tizen
+
+The [Firebase Database for Flutter](https://pub.dev/packages/firebase_database) implementation for Tizen.
+
+It offers experimental features for using Firebase on Flutter for Tizen. It works by wrapping cross-compiled libraries that are based on the [Firebase C++ SDK](https://github.com/firebase/firebase-cpp-sdk) for Linux.
+
+# Usage
+
+To use this package, you need to include `firebase_database_tizen` as a dependency alongside `firebase_database` in your `pubspec.yaml`. Please note that `firebase_database_tizen` implementation is not officially endorsed for `firebase_database`.
+
+```yaml
+dependencies:
+ firebase_database: 10.0.9
+ firebase_database_tizen: ^0.1.0
+```
+
+Then you can import `firebase_database` in your Dart code:
+
+```dart
+import 'package:firebase_database/firebase_database.dart';
+```
+
+## Required privileges
+
+To use this plugin in a Tizen application, you may need to declare the following privileges in your `tizen-manifest.xml` file.
+
+```xml
+
+ http://tizen.org/privilege/internet
+
+```
+
+- `http://tizen.org/privilege/internet` allows the application to access the Internet.
+
+For the details on Tizen privileges, please see [Tizen Docs: API Privileges](https://docs.tizen.org/application/dotnet/get-started/api-privileges).
+
+
+# Limitations
+
+The following features are currently unavailable as they're not supported by the version of Firebase C++ SDK for Linux that this plugin is currently based on.
+
+- Using Firebase Local Emulator Suite.
+- Using `FirebaseDatabase#setPersistenceCacheSizeBytes()` for the on-disk data.
+- Using `Query#startAfter()` or `Query#endBefore()` method to add a cursor to a query.
diff --git a/packages/firebase_database/analysis_options.yaml b/packages/firebase_database/analysis_options.yaml
new file mode 100644
index 0000000..216f401
--- /dev/null
+++ b/packages/firebase_database/analysis_options.yaml
@@ -0,0 +1,5 @@
+include: ../../analysis_options.yaml
+
+linter:
+ rules:
+ public_member_api_docs: true
diff --git a/packages/firebase_database/example/.gitignore b/packages/firebase_database/example/.gitignore
new file mode 100644
index 0000000..f0f3dcb
--- /dev/null
+++ b/packages/firebase_database/example/.gitignore
@@ -0,0 +1,38 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# VS Code related
+.vscode/
+
+# Flutter/Dart/Pub related
+/pubspec.lock
+**/doc/api/
+**/ios/Flutter/.last_build_id
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.packages
+.pub-cache/
+.pub/
+/build/
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
diff --git a/packages/firebase_database/example/README.md b/packages/firebase_database/example/README.md
new file mode 100644
index 0000000..63a83f0
--- /dev/null
+++ b/packages/firebase_database/example/README.md
@@ -0,0 +1,4 @@
+# Example
+
+A test app for firebase_database_tizen plugin (e2e).
+
diff --git a/packages/firebase_database/example/analysis_options.yaml b/packages/firebase_database/example/analysis_options.yaml
new file mode 100644
index 0000000..a174f61
--- /dev/null
+++ b/packages/firebase_database/example/analysis_options.yaml
@@ -0,0 +1,10 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# in the LICENSE file.
+
+include: ../../../analysis_options.yaml
+linter:
+ rules:
+ avoid_print: false
+ depend_on_referenced_packages: false
+ library_private_types_in_public_api: false
diff --git a/packages/firebase_database/example/integration_test/firebase_database/data_snapshot_e2e.dart b/packages/firebase_database/example/integration_test/firebase_database/data_snapshot_e2e.dart
new file mode 100644
index 0000000..2a5259e
--- /dev/null
+++ b/packages/firebase_database/example/integration_test/firebase_database/data_snapshot_e2e.dart
@@ -0,0 +1,154 @@
+// Copyright 2022, the Chromium project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:firebase_database/firebase_database.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void setupDataSnapshotTests() {
+ group('DataSnapshot', () {
+ late DatabaseReference ref;
+
+ setUp(() async {
+ ref = FirebaseDatabase.instance.ref('tests');
+
+ // Wipe the database before each test
+ await ref.remove();
+ });
+
+ test('it returns the correct key', () async {
+ final s = await ref.get();
+ expect(s.key, 'tests');
+ });
+
+ test('it returns a string value', () async {
+ await ref.set('foo');
+ final s = await ref.get();
+ expect(s.value, 'foo');
+ });
+
+ test('it returns a number value', () async {
+ await ref.set(123);
+ final s = await ref.get();
+ expect(s.value, 123);
+ });
+
+ test('it returns a bool value', () async {
+ await ref.set(false);
+ final s = await ref.get();
+ expect(s.value, false);
+ });
+
+ test('it returns a null value', () async {
+ await ref.set(null);
+ final s = await ref.get();
+ expect(s.value, isNull);
+ });
+
+ test('it returns a List value', () async {
+ final data = [
+ 'a',
+ 2,
+ true,
+ ['foo'],
+ {
+ 0: 'hello',
+ 1: 'foo',
+ }
+ ];
+ await ref.set(data);
+ final s = await ref.get();
+ expect(
+ s.value,
+ equals([
+ 'a',
+ 2,
+ true,
+ ['foo'],
+ ['hello', 'foo']
+ ]),
+ );
+ });
+
+ test('it returns a Map value', () async {
+ final data = {'foo': 'bar'};
+ await ref.set(data);
+ final s = await ref.get();
+ expect(s.value, equals(data));
+ });
+
+ test('non-string Map keys are converted to strings', () async {
+ final data = {1: 'foo', 2: 'bar', 'foo': 'bar'};
+ await ref.set(data);
+ final s = await ref.get();
+ expect(s.value, equals({'1': 'foo', '2': 'bar', 'foo': 'bar'}));
+ });
+
+ test('setWithPriority returns the correct priority', () async {
+ await ref.setWithPriority('foo', 1);
+ final s = await ref.get();
+ expect(s.priority, 1);
+ });
+
+ test('setPriority returns the correct priority', () async {
+ await ref.set('foo');
+ await ref.setPriority(2);
+ final s = await ref.get();
+ expect(s.priority, 2);
+ });
+
+ test('exists returns true', () async {
+ await ref.set('foo');
+ final s = await ref.get();
+ expect(s.exists, isTrue);
+ });
+
+ test('exists returns false', () async {
+ final s = await ref.get();
+ expect(s.exists, isFalse);
+ });
+
+ test('hasChild returns false', () async {
+ final s = await ref.get();
+ expect(s.hasChild('bar'), isFalse);
+ });
+
+ test('hasChild returns true', () async {
+ await ref.set({
+ 'foo': {'bar': 'baz'}
+ });
+ final s = await ref.get();
+ expect(s.hasChild('bar'), isFalse);
+ });
+
+ test('child returns the correct snapshot for lists', () async {
+ await ref.set([0, 1]);
+ final s = await ref.get();
+ expect(s.child('1'), isA());
+ expect(s.child('1').value, 1);
+ });
+
+ test('child returns the correct snapshot', () async {
+ await ref.set({
+ 'foo': {'bar': 'baz'}
+ });
+ final s = await ref.get();
+ expect(s.child('foo/bar'), isA());
+ expect(s.child('foo/bar').value, 'baz');
+ });
+
+ test('children returns the children in order', () async {
+ await ref.set({
+ 'a': 3,
+ 'b': 2,
+ 'c': 1,
+ });
+ final s = await ref.orderByValue().get();
+
+ List children = s.children.toList();
+ expect(children[0].value, 1);
+ expect(children[1].value, 2);
+ expect(children[2].value, 3);
+ });
+ });
+}
diff --git a/packages/firebase_database/example/integration_test/firebase_database/database_e2e.dart b/packages/firebase_database/example/integration_test/firebase_database/database_e2e.dart
new file mode 100644
index 0000000..bf79f23
--- /dev/null
+++ b/packages/firebase_database/example/integration_test/firebase_database/database_e2e.dart
@@ -0,0 +1,93 @@
+// Copyright 2022, the Chromium project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:flutter_test/flutter_test.dart';
+
+import 'firebase_database_e2e_test.dart';
+import '../../lib/firebase_options.dart';
+
+void setupDatabaseTests() {
+ group('FirebaseDatabase.ref()', () {
+ setUpAll(() async {
+ await database.ref('tests/flutterfire').set(0);
+ });
+
+ test('returns a correct reference', () async {
+ final ref = database.ref('tests/flutterfire');
+ expect(ref.key, 'flutterfire');
+ expect(ref.parent, isNotNull);
+ expect(ref.parent!.key, 'tests');
+ expect(ref.parent!.parent, isNotNull);
+ expect(ref.parent!.parent?.key, isNull);
+
+ final snapshot = await ref.get();
+ expect(snapshot.key, 'flutterfire');
+ expect(snapshot.value, 0);
+ });
+
+ test(
+ 'root reference path returns as "/"',
+ () async {
+ final rootRef = database.ref();
+ expect(rootRef.path, '/');
+ expect(rootRef.key, isNull);
+ expect(rootRef.parent, isNull);
+ },
+ );
+
+ test(
+ 'returns a reference to the root of the database if no path specified',
+ () async {
+ final rootRef = database.ref();
+ expect(rootRef.key, isNull);
+ expect(rootRef.parent, isNull);
+
+ final childRef = rootRef.child('tests/flutterfire');
+ final snapshot = await childRef.get();
+ expect(snapshot.key, 'flutterfire');
+ expect(snapshot.value, 0);
+ },
+ );
+ });
+
+ group('FirebaseDatabase.refFromURL()', () {
+ final String databaseURL =
+ DefaultFirebaseOptions.currentPlatform.databaseURL ?? '';
+
+ test('correctly returns a ref for database root', () async {
+ final ref = database.refFromURL(databaseURL);
+ expect(ref.key, isNull);
+
+ final refWithTrailingSlash = database.refFromURL(
+ '${databaseURL}/',
+ );
+ expect(refWithTrailingSlash.key, isNull);
+ });
+
+ test('correctly returns a ref for any database path', () async {
+ final ref = database.refFromURL(
+ '${databaseURL}/foo',
+ );
+ expect(ref.key, 'foo');
+
+ final refWithNestedPath = database.refFromURL(
+ '${databaseURL}/foo/bar',
+ );
+ expect(refWithNestedPath.parent?.key, 'foo');
+ expect(refWithNestedPath.key, 'bar');
+ });
+
+ test('throws [ArgumentError] if not a valid https:// url', () async {
+ expect(() => database.refFromURL('foo'), throwsArgumentError);
+ });
+
+ test('throws [ArgumentError] if database url does not match instance url',
+ () async {
+ expect(
+ () => database.refFromURL('https://some-other-database.firebaseio.com'),
+ throwsArgumentError,
+ );
+ });
+ });
+}
diff --git a/packages/firebase_database/example/integration_test/firebase_database/database_reference_e2e.dart b/packages/firebase_database/example/integration_test/firebase_database/database_reference_e2e.dart
new file mode 100644
index 0000000..33c5fbb
--- /dev/null
+++ b/packages/firebase_database/example/integration_test/firebase_database/database_reference_e2e.dart
@@ -0,0 +1,187 @@
+// Copyright 2022, the Chromium project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:math';
+
+import 'package:firebase_core/firebase_core.dart';
+import 'package:firebase_database/firebase_database.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+import 'firebase_database_e2e_test.dart';
+
+void setupDatabaseReferenceTests() {
+ group('DatabaseReference', () {
+ late DatabaseReference ref;
+
+ setUp(() async {
+ ref = database.ref('tests');
+ await ref.remove();
+ });
+
+ group('set()', () {
+ test('sets value', () async {
+ final v = Random.secure().nextInt(1024);
+ await ref.set(v);
+ final actual = await ref.get();
+ expect(actual.value, v);
+ });
+
+ test(
+ 'throws "permission-denied" on a ref with no read permission',
+ () async {
+ await expectLater(
+ database.ref('denied_read').get(),
+ throwsA(
+ isA()
+ .having(
+ (error) => error.code,
+ 'code',
+ 'permission-denied',
+ )
+ .having(
+ (error) => error.message,
+ 'message',
+ predicate(
+ (String message) =>
+ message.contains("doesn't have permission"),
+ ),
+ ),
+ ),
+ );
+ },
+ skip: true, // TODO Fails on CI even though works locally
+ );
+
+ test('removes a value if set to null', () async {
+ final v = Random.secure().nextInt(1024);
+ await ref.set(v);
+ final before = await ref.get();
+ expect(before.value, v);
+
+ await ref.set(null);
+ final after = await ref.get();
+ expect(after.value, isNull);
+ expect(after.exists, isFalse);
+ });
+ });
+
+ group('setPriority()', () {
+ test('sets a priority', () async {
+ await ref.set('foo');
+ await ref.setPriority(2);
+ final snapshot = await ref.get();
+ expect(snapshot.priority, 2);
+ });
+ });
+
+ group('setWithPriority()', () {
+ test('sets a non-null value with a non-null priority', () async {
+ await Future.wait([
+ ref.child('first').setWithPriority(1, 10),
+ ref.child('second').setWithPriority(2, 1),
+ ref.child('third').setWithPriority(3, 5),
+ ]);
+
+ final snapshot = await ref.orderByPriority().get();
+ final keys = snapshot.children.map((child) => child.key).toList();
+ expect(keys, ['second', 'third', 'first']);
+ });
+ });
+
+ group('update()', () {
+ test('updates value at given location', () async {
+ await ref.set({'foo': 'bar'});
+ final newValue = Random.secure().nextInt(255) + 1;
+ await ref.update({'bar': newValue});
+ final actual = await ref.get();
+
+ expect(actual.value, {
+ 'foo': 'bar',
+ 'bar': newValue,
+ });
+ });
+ });
+
+ group('runTransaction()', () {
+ setUp(() async {
+ await ref.set(0);
+ });
+
+ test('aborts a transaction', () async {
+ await ref.set(5);
+ final snapshot = await ref.get();
+ expect(snapshot.value, 5);
+
+ final result = await ref.runTransaction((value) {
+ // NOTE(daeyeon): When testing this in firebase (not emulator), the
+ // value firstly come is `null`, even though we actually set it to 5
+ // just above. This is actually expected behavior according to the
+ // documentation(https://firebase.google.com/docs/database/admin/save-data#transaction-function-is-called-multiple-times).
+ // This transaction handler can be called multiple times and must be
+ // able to handle 'null' data. Even if there is existing data in your
+ // database it may not be locally cached when the transaction function
+ // is run.
+ //
+ // If the value is `null`, the handler returns transaction.success
+ // with 1 as a next value, and the internal `onCompleteCallback` will
+ // exit with no error. That means that `committed` in the result will
+ // be true rather false this TC expected. This TC maybe pass only when
+ // testing with the emulator that doesn't seem to work with C++ SDK.
+ // Thus, we skip this test for now until we can verify this TC.
+ final nextValue = (value as int? ?? 0) + 1;
+ if (nextValue > 5) {
+ return Transaction.abort();
+ }
+ return Transaction.success(nextValue);
+ });
+
+ expect(result.committed, false);
+ expect(result.snapshot.value, 5);
+ }, skip: 'TODO: Review TC for defects.');
+
+ test('executes transaction', () async {
+ final snapshot = await ref.get();
+ final value = (snapshot.value ?? 0) as int;
+ final result = await ref.runTransaction((value) {
+ return Transaction.success((value as int? ?? 0) + 1);
+ });
+
+ expect(result.committed, true);
+ expect((result.snapshot.value ?? 0) as int > value, true);
+ expect(result.snapshot.key, ref.key);
+ });
+
+ test('get primitive list values', () async {
+ List data = ['first', 'second'];
+ final FirebaseDatabase database = FirebaseDatabase.instance;
+ final DatabaseReference ref = database.ref('tests/list-values');
+
+ await ref.set({'list': data});
+
+ final transactionResult = await ref.runTransaction((mutableData) {
+ return Transaction.success(mutableData);
+ });
+
+ var value = transactionResult.snapshot.value as dynamic;
+ expect(value, isNotNull);
+ expect(value['list'], data);
+ });
+
+ test('Server.increment', () async {
+ final FirebaseDatabase database = FirebaseDatabase.instance;
+ final DatabaseReference ref = database.ref('tests/server-increment');
+ await ref.set(ServerValue.increment(1.5));
+
+ final snap = await ref.get();
+ var value = snap.value;
+ expect(value, 1.5);
+
+ await ref.set(ServerValue.increment(1));
+ final snap2 = await ref.get();
+ var value2 = snap2.value;
+ expect(value2, 2.5);
+ });
+ });
+ });
+}
diff --git a/packages/firebase_database/example/integration_test/firebase_database/extra_e2e.dart b/packages/firebase_database/example/integration_test/firebase_database/extra_e2e.dart
new file mode 100644
index 0000000..4ca2e58
--- /dev/null
+++ b/packages/firebase_database/example/integration_test/firebase_database/extra_e2e.dart
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2023-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import 'package:firebase_database/firebase_database.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void setupExtraTests() {
+ group('Database Extra', () {
+ test('PurgeOutstandingWrites()', () async {
+ FirebaseDatabase.instance.purgeOutstandingWrites();
+ });
+ });
+
+ group('Query Extra', () {
+ late DatabaseReference ref;
+
+ setUp(() async {
+ ref = FirebaseDatabase.instance.ref('tests');
+
+ // Wipe the database before each test
+ await ref.remove();
+ });
+
+ test('keepSynced()', () async {
+ ref.keepSynced(true);
+ });
+ });
+}
diff --git a/packages/firebase_database/example/integration_test/firebase_database/firebase_database_configuration_e2e.dart b/packages/firebase_database/example/integration_test/firebase_database/firebase_database_configuration_e2e.dart
new file mode 100644
index 0000000..7cb4b66
--- /dev/null
+++ b/packages/firebase_database/example/integration_test/firebase_database/firebase_database_configuration_e2e.dart
@@ -0,0 +1,41 @@
+// Copyright 2022, the Chromium project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:flutter/foundation.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+import 'firebase_database_e2e_test.dart';
+
+const MAX_CACHE_SIZE = 100 * 1024 * 1024;
+const MIN_CACHE_SIZE = 1042 * 1024;
+
+void setupConfigurationTests() {
+ group('FirebaseDatabase configuration', () {
+ test(
+ 'setPersistenceCacheSizeBytes Integer',
+ () {
+ database.setPersistenceCacheSizeBytes(MIN_CACHE_SIZE);
+ },
+ // Skipped because it is not supported on web
+ skip: kIsWeb,
+ );
+
+ test(
+ 'setPersistenceCacheSizeBytes Long',
+ () {
+ database.setPersistenceCacheSizeBytes(MAX_CACHE_SIZE);
+ },
+ // Skipped because it is not supported on web
+ skip: kIsWeb,
+ );
+
+ test('setLoggingEnabled to true', () {
+ database.setLoggingEnabled(true);
+ });
+
+ test('setLoggingEnabled to false', () {
+ database.setLoggingEnabled(false);
+ });
+ });
+}
diff --git a/packages/firebase_database/example/integration_test/firebase_database/firebase_database_e2e_test.dart b/packages/firebase_database/example/integration_test/firebase_database/firebase_database_e2e_test.dart
new file mode 100644
index 0000000..f9e15b0
--- /dev/null
+++ b/packages/firebase_database/example/integration_test/firebase_database/firebase_database_e2e_test.dart
@@ -0,0 +1,56 @@
+// Copyright 2022, the Chromium project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:firebase_core/firebase_core.dart';
+import 'package:firebase_database/firebase_database.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:integration_test/integration_test.dart';
+import 'package:tests/firebase_options.dart';
+
+import 'data_snapshot_e2e.dart';
+import 'database_e2e.dart';
+import 'database_reference_e2e.dart';
+import 'firebase_database_configuration_e2e.dart';
+import 'query_e2e.dart';
+import 'extra_e2e.dart';
+import 'on_disconnect_e2e.dart';
+
+late FirebaseDatabase database;
+
+// The port we've set the Firebase Database emulator to run on via the
+// `firebase.json` configuration file.
+const emulatorPort = 9000;
+
+// Android device emulators consider localhost of the host machine as 10.0.2.2
+// so let's use that if running on Android.
+final emulatorHost =
+ (!kIsWeb && defaultTargetPlatform == TargetPlatform.android)
+ ? '10.0.2.2'
+ : 'localhost';
+
+void main() {
+ IntegrationTestWidgetsFlutterBinding.ensureInitialized();
+
+ group('firebase_database', () {
+ setUpAll(() async {
+ await Firebase.initializeApp(
+ options: DefaultFirebaseOptions.currentPlatform,
+ );
+ database = FirebaseDatabase.instance;
+ database.useDatabaseEmulator(emulatorHost, emulatorPort);
+ await database.goOnline();
+ });
+
+ setupConfigurationTests();
+ setupDatabaseTests();
+ setupDatabaseReferenceTests();
+ setupQueryTests();
+ setupDataSnapshotTests();
+ setupExtraTests();
+ setupOnDisconnectTests();
+ // TODO(ehesp): Fix broken tests
+ // runOnDisconnectTests();
+ });
+}
diff --git a/packages/firebase_database/example/integration_test/firebase_database/on_disconnect_e2e.dart b/packages/firebase_database/example/integration_test/firebase_database/on_disconnect_e2e.dart
new file mode 100644
index 0000000..33a2b10
--- /dev/null
+++ b/packages/firebase_database/example/integration_test/firebase_database/on_disconnect_e2e.dart
@@ -0,0 +1,79 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:firebase_database/firebase_database.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void setupOnDisconnectTests() {
+ group('OnDisconnect', () {
+ late FirebaseDatabase database;
+ late DatabaseReference ref;
+
+ setUp(() async {
+ database = FirebaseDatabase.instance;
+ ref = database.ref('tests');
+
+ // Wipe the database before each test
+ await ref.remove();
+ });
+
+ Future toggleState() async {
+ await database.goOffline();
+ await database.goOnline();
+ }
+
+ tearDown(() async {
+ await FirebaseDatabase.instance.goOnline();
+ });
+
+ test('sets a value on disconnect', () async {
+ await ref.onDisconnect().set('foo');
+ await toggleState();
+ var snapshot = await ref.get();
+ expect(snapshot.value, 'foo');
+ });
+
+ test('sets a value with priority on disconnect', () async {
+ await ref.onDisconnect().setWithPriority('foo', 3);
+ await toggleState();
+ var snapshot = await ref.get();
+ expect(snapshot.value, 'foo');
+ expect(snapshot.priority, 3);
+ });
+
+ test('removes a node on disconnect', () async {
+ await ref.set('foo');
+ await ref.onDisconnect().remove();
+ await toggleState();
+ var snapshot = await ref.get();
+ expect(snapshot.exists, isFalse);
+ });
+
+ test('updates a node on disconnect', () async {
+ await ref.set({'foo': 'bar'});
+ await ref.onDisconnect().update({'bar': 'baz'});
+ await toggleState();
+ var snapshot = await ref.get();
+ expect(
+ snapshot.value,
+ equals({
+ 'foo': 'bar',
+ 'bar': 'baz',
+ }),
+ );
+ });
+
+ test('cancels disconnect operations', () async {
+ await ref.set('foo');
+ await ref.onDisconnect().remove();
+ await ref.onDisconnect().cancel();
+ await toggleState();
+ var snapshot = await ref.get();
+ expect(
+ snapshot.value,
+ 'foo',
+ );
+ });
+ });
+}
diff --git a/packages/firebase_database/example/integration_test/firebase_database/query_e2e.dart b/packages/firebase_database/example/integration_test/firebase_database/query_e2e.dart
new file mode 100644
index 0000000..572459d
--- /dev/null
+++ b/packages/firebase_database/example/integration_test/firebase_database/query_e2e.dart
@@ -0,0 +1,508 @@
+// Copyright 2022, the Chromium project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:collection/collection.dart';
+import 'package:firebase_database/firebase_database.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void setupQueryTests() {
+ group('Query', () {
+ late DatabaseReference ref;
+
+ setUp(() async {
+ ref = FirebaseDatabase.instance.ref('tests');
+
+ // Wipe the database before each test
+ await ref.remove();
+ });
+
+ group('startAt', () {
+ test('returns null when no order modifier is applied', () async {
+ await ref.set({
+ 'a': 1,
+ 'b': 2,
+ 'c': 3,
+ });
+
+ final snapshot = await ref.startAt(2).get();
+ expect(snapshot.value, isNull);
+ });
+
+ test('starts at the correct value', () async {
+ await ref.set({
+ 'a': 1,
+ 'b': 2,
+ 'c': 3,
+ 'd': 4,
+ });
+
+ final snapshot = await ref.orderByValue().startAt(2).get();
+
+ final expected = ['b', 'c', 'd'];
+
+ expect(snapshot.children.length, expected.length);
+ snapshot.children.toList().forEachIndexed((i, childSnapshot) {
+ expect(childSnapshot.key, expected[i]);
+ });
+ });
+ });
+
+ group('startAfter', () {
+ test('returns null when no order modifier is applied', () async {
+ await ref.set({
+ 'a': 1,
+ 'b': 2,
+ 'c': 3,
+ });
+
+ final snapshot = await ref.startAfter(2).get();
+ expect(snapshot.value, isNull);
+ });
+
+ test('starts after the correct value', () async {
+ await ref.set({
+ 'a': 1,
+ 'b': 2,
+ 'c': 3,
+ 'd': 4,
+ });
+
+ // TODO(ehesp): Using `get` returns the wrong results. Have flagged with SDK team.
+ final e = await ref.orderByValue().startAfter(2).once();
+
+ final expected = ['c', 'd'];
+
+ expect(e.snapshot.children.length, expected.length);
+ e.snapshot.children.toList().forEachIndexed((i, childSnapshot) {
+ expect(childSnapshot.key, expected[i]);
+ });
+ });
+ }, skip: "'startAfter' isn't supported by C++ SDK");
+
+ group('endAt', () {
+ test('returns all values when no order modifier is applied', () async {
+ await ref.set({
+ 'a': 1,
+ 'b': 2,
+ 'c': 3,
+ });
+
+ final expected = ['a', 'b', 'c'];
+
+ final snapshot = await ref.endAt(2).get();
+
+ expect(snapshot.children.length, expected.length);
+ snapshot.children.toList().forEachIndexed((i, childSnapshot) {
+ expect(childSnapshot.key, expected[i]);
+ });
+ });
+
+ test('ends at the correct value', () async {
+ await ref.set({
+ 'a': 1,
+ 'b': 2,
+ 'c': 3,
+ 'd': 4,
+ });
+
+ final snapshot = await ref.orderByValue().endAt(2).get();
+
+ final expected = ['a', 'b'];
+
+ expect(snapshot.children.length, expected.length);
+ snapshot.children.toList().forEachIndexed((i, childSnapshot) {
+ expect(childSnapshot.key, expected[i]);
+ });
+ });
+ });
+
+ group('endBefore', () {
+ test('returns all values when no order modifier is applied', () async {
+ await ref.set({
+ 'a': 1,
+ 'b': 2,
+ 'c': 3,
+ });
+
+ final expected = ['a', 'b', 'c'];
+
+ final snapshot = await ref.endBefore(2).get();
+
+ expect(snapshot.children.length, expected.length);
+ snapshot.children.toList().forEachIndexed((i, childSnapshot) {
+ expect(childSnapshot.key, expected[i]);
+ });
+ });
+
+ test('ends before the correct value', () async {
+ await ref.set({
+ 'a': 1,
+ 'b': 2,
+ 'c': 3,
+ 'd': 4,
+ });
+
+ final snapshot = await ref.orderByValue().endBefore(2).get();
+
+ final expected = ['a'];
+
+ expect(snapshot.children.length, expected.length);
+ snapshot.children.toList().forEachIndexed((i, childSnapshot) {
+ expect(childSnapshot.key, expected[i]);
+ });
+ });
+ }, skip: "'endBefore' isn't supported by C++ SDK");
+
+ group('equalTo', () {
+ test('returns null when no order modifier is applied', () async {
+ await ref.set({
+ 'a': 1,
+ 'b': 2,
+ 'c': 3,
+ });
+
+ final snapshot = await ref.equalTo(2).get();
+ expect(snapshot.value, isNull);
+ });
+
+ test('returns the correct value', () async {
+ await ref.set({
+ 'a': 1,
+ 'b': 2,
+ 'c': 3,
+ 'd': 4,
+ 'e': 2,
+ });
+
+ final snapshot = await ref.orderByValue().equalTo(2).get();
+
+ final expected = ['b', 'e'];
+
+ expect(snapshot.children.length, expected.length);
+ snapshot.children.toList().forEachIndexed((i, childSnapshot) {
+ expect(childSnapshot.key, expected[i]);
+ });
+ });
+ });
+
+ group('limitToFirst', () {
+ test('returns a limited array', () async {
+ await ref.set({
+ 0: 'foo',
+ 1: 'bar',
+ 2: 'baz',
+ });
+
+ final snapshot = await ref.limitToFirst(2).get();
+
+ final expected = ['foo', 'bar'];
+ expect(snapshot.value, equals(expected));
+ });
+
+ test('returns a limited object', () async {
+ await ref.set({
+ 'a': 'foo',
+ 'b': 'bar',
+ 'c': 'baz',
+ });
+
+ final snapshot = await ref.limitToFirst(2).get();
+
+ final expected = {
+ 'a': 'foo',
+ 'b': 'bar',
+ };
+
+ expect(snapshot.value, equals(expected));
+ });
+
+ test('returns null when no limit is possible', () async {
+ await ref.set('foo');
+
+ final snapshot = await ref.limitToFirst(2).get();
+
+ expect(snapshot.value, isNull);
+ });
+ });
+
+ group('limitToLast', () {
+ test('returns a limited array', () async {
+ await ref.set({
+ 0: 'foo',
+ 1: 'bar',
+ 2: 'baz',
+ });
+
+ final snapshot = await ref.limitToLast(2).get();
+
+ final expected = [null, 'bar', 'baz'];
+ expect(snapshot.value, equals(expected));
+ });
+
+ test('returns a limited object', () async {
+ await ref.set({
+ 'a': 'foo',
+ 'b': 'bar',
+ 'c': 'baz',
+ });
+
+ final snapshot = await ref.limitToLast(2).get();
+
+ final expected = {
+ 'b': 'bar',
+ 'c': 'baz',
+ };
+
+ expect(snapshot.value, equals(expected));
+ });
+
+ test('returns null when no limit is possible', () async {
+ await ref.set('foo');
+
+ final snapshot = await ref.limitToLast(2).get();
+
+ expect(snapshot.value, isNull);
+ });
+ });
+
+ group('orderByChild', () {
+ test('orders by a child value', () async {
+ await ref.set({
+ 'a': {
+ 'string': 'foo',
+ 'number': 10,
+ },
+ 'b': {
+ 'string': 'bar',
+ 'number': 5,
+ },
+ 'c': {
+ 'string': 'baz',
+ 'number': 8,
+ },
+ });
+
+ final snapshot = await ref.orderByChild('number').get();
+
+ final expected = ['b', 'c', 'a'];
+ expect(snapshot.children.length, equals(expected.length));
+ snapshot.children.toList().forEachIndexed((i, childSnapshot) {
+ expect(childSnapshot.key, expected[i]);
+ });
+ });
+ });
+
+ group('orderByKey', () {
+ test('orders by a key', () async {
+ await ref.set({
+ 'b': {
+ 'string': 'bar',
+ 'number': 5,
+ },
+ 'a': {
+ 'string': 'foo',
+ 'number': 10,
+ },
+ 'c': {
+ 'string': 'baz',
+ 'number': 8,
+ },
+ });
+
+ final snapshot = await ref.orderByKey().get();
+
+ final expected = ['a', 'b', 'c'];
+
+ expect(snapshot.children.length, expected.length);
+ snapshot.children.toList().forEachIndexed((i, childSnapshot) {
+ expect(childSnapshot.key, expected[i]);
+ });
+ });
+ });
+
+ group('orderByPriority', () {
+ test('orders by priority', () async {
+ await ref.set({
+ 'a': {
+ 'string': 'foo',
+ 'number': 10,
+ },
+ 'b': {
+ 'string': 'bar',
+ 'number': 5,
+ },
+ 'c': {
+ 'string': 'baz',
+ 'number': 8,
+ },
+ });
+
+ await Future.wait([
+ ref.child('a').setPriority(2),
+ ref.child('b').setPriority(3),
+ ref.child('c').setPriority(1),
+ ]);
+
+ final snapshot = await ref.orderByPriority().get();
+
+ final expected = ['c', 'a', 'b'];
+ expect(snapshot.children.length, equals(expected.length));
+ snapshot.children.toList().forEachIndexed((i, childSnapshot) {
+ expect(childSnapshot.key, expected[i]);
+ });
+ });
+ });
+
+ group('orderByValue', () {
+ test('orders by a value', () async {
+ await ref.set({
+ 'a': 2,
+ 'b': 3,
+ 'c': 1,
+ });
+
+ await Future.wait([
+ ref.child('a').setPriority(2),
+ ref.child('b').setPriority(3),
+ ref.child('c').setPriority(1),
+ ]);
+
+ final snapshot = await ref.orderByValue().get();
+
+ final expected = ['c', 'a', 'b'];
+ expect(snapshot.children.length, equals(expected.length));
+ snapshot.children.toList().forEachIndexed((i, childSnapshot) {
+ expect(childSnapshot.key, expected[i]);
+ });
+ });
+ });
+
+ group('onChildAdded', () {
+ test(
+ 'emits an event when a child is added',
+ () async {
+ expect(
+ ref.onChildAdded,
+ emitsInOrder([
+ isA()
+ .having((s) => s.snapshot.value, 'value', 'foo')
+ .having((e) => e.type, 'type', DatabaseEventType.childAdded),
+ isA()
+ .having((s) => s.snapshot.value, 'value', 'bar')
+ .having((e) => e.type, 'type', DatabaseEventType.childAdded),
+ ]),
+ );
+
+ // NOTE(daeyeon): The event listener must be registered before the
+ // following operations take place. Similar issues can be found in
+ // other event-related TCs and they are addressed by one second delay.
+ await Future.delayed(const Duration(seconds: 1));
+
+ await ref.child('foo').set('foo');
+ await ref.child('bar').set('bar');
+ },
+ retry: 2,
+ );
+ });
+
+ group('onChildRemoved', () {
+ test(
+ 'emits an event when a child is removed',
+ () async {
+ await ref.child('foo').set('foo');
+ await ref.child('bar').set('bar');
+
+ expect(
+ ref.onChildRemoved,
+ emitsInOrder([
+ isA()
+ .having((s) => s.snapshot.value, 'value', 'bar')
+ .having(
+ (e) => e.type,
+ 'type',
+ DatabaseEventType.childRemoved,
+ ),
+ ]),
+ );
+ // Give time for listen to be registered on native.
+ // TODO is there a better way to do this?
+ await Future.delayed(const Duration(seconds: 1));
+ await ref.child('bar').remove();
+ },
+ retry: 2,
+ );
+ });
+
+ group('onChildChanged', () {
+ test(
+ 'emits an event when a child is changed',
+ () async {
+ await ref.child('foo').set('foo');
+ await ref.child('bar').set('bar');
+
+ expect(
+ ref.onChildChanged,
+ emitsInOrder([
+ isA()
+ .having((s) => s.snapshot.key, 'key', 'bar')
+ .having((s) => s.snapshot.value, 'value', 'baz')
+ .having(
+ (e) => e.type,
+ 'type',
+ DatabaseEventType.childChanged,
+ ),
+ isA()
+ .having((s) => s.snapshot.key, 'key', 'foo')
+ .having((s) => s.snapshot.value, 'value', 'bar')
+ .having(
+ (e) => e.type,
+ 'type',
+ DatabaseEventType.childChanged,
+ ),
+ ]),
+ );
+ // Give time for listen to be registered on native.
+ // TODO is there a better way to do this?
+ await Future.delayed(const Duration(seconds: 1));
+ await ref.child('bar').set('baz');
+ await ref.child('foo').set('bar');
+ },
+ retry: 2,
+ );
+ });
+
+ group('onChildMoved', () {
+ test(
+ 'emits an event when a child is moved',
+ () async {
+ await ref.set({
+ 'alex': {'nuggets': 60},
+ 'rob': {'nuggets': 56},
+ 'vassili': {'nuggets': 55.5},
+ 'tony': {'nuggets': 52},
+ 'greg': {'nuggets': 52},
+ });
+
+ expect(
+ ref.orderByChild('nuggets').onChildMoved,
+ emitsInOrder([
+ isA().having((s) => s.snapshot.value, 'value', {
+ 'nuggets': 57
+ }).having((e) => e.type, 'type', DatabaseEventType.childMoved),
+ isA().having((s) => s.snapshot.value, 'value', {
+ 'nuggets': 61
+ }).having((e) => e.type, 'type', DatabaseEventType.childMoved),
+ ]),
+ );
+ // Give time for listen to be registered on native.
+ // TODO is there a better way to do this?
+ await Future.delayed(const Duration(seconds: 1));
+ await ref.child('greg/nuggets').set(57);
+ await ref.child('rob/nuggets').set(61);
+ },
+ retry: 2,
+ );
+ });
+ });
+}
diff --git a/packages/firebase_database/example/lib/firebase_options.dart b/packages/firebase_database/example/lib/firebase_options.dart
new file mode 100644
index 0000000..fb3c146
--- /dev/null
+++ b/packages/firebase_database/example/lib/firebase_options.dart
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2023-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
+import 'package:flutter/foundation.dart'
+ show defaultTargetPlatform, TargetPlatform;
+
+class DefaultFirebaseOptions {
+ static FirebaseOptions get currentPlatform {
+ switch (defaultTargetPlatform) {
+ case TargetPlatform.linux:
+ // Note: To find out if you are using the Tizen platform, refer to the link below.
+ // https://github.com/flutter-tizen/flutter-tizen/issues/482#issuecomment-1441139704
+ return tizen;
+ default:
+ throw UnsupportedError(
+ 'DefaultFirebaseOptions are not supported for this platform.',
+ );
+ }
+ }
+
+ static String get emulatorHost {
+ return 'PLACEHOLDER';
+ }
+
+ static const FirebaseOptions tizen = FirebaseOptions(
+ apiKey: 'PLACEHOLDER',
+ appId: 'PLACEHOLDER',
+ messagingSenderId: 'PLACEHOLDER',
+ projectId: 'PLACEHOLDER',
+ databaseURL: 'PLACEHOLDER',
+ storageBucket: 'PLACEHOLDER',
+ );
+}
diff --git a/packages/firebase_database/example/lib/main.dart b/packages/firebase_database/example/lib/main.dart
new file mode 100644
index 0000000..23846fa
--- /dev/null
+++ b/packages/firebase_database/example/lib/main.dart
@@ -0,0 +1,240 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:firebase_core/firebase_core.dart';
+import 'package:firebase_database/firebase_database.dart';
+import 'package:firebase_database/ui/firebase_animated_list.dart';
+import 'package:flutter/foundation.dart' show defaultTargetPlatform, kIsWeb;
+import 'package:flutter/material.dart';
+
+import 'firebase_options.dart';
+
+// Change to false to use live database instance.
+const USE_DATABASE_EMULATOR = true;
+// The port we've set the Firebase Database emulator to run on via the
+// `firebase.json` configuration file.
+const emulatorPort = 9000;
+// Android device emulators consider localhost of the host machine as 10.0.2.2
+// so let's use that if running on Android.
+final emulatorHost =
+ (!kIsWeb && defaultTargetPlatform == TargetPlatform.android)
+ ? '10.0.2.2'
+ : 'localhost';
+
+Future main() async {
+ WidgetsFlutterBinding.ensureInitialized();
+ await Firebase.initializeApp(
+ options: DefaultFirebaseOptions.currentPlatform,
+ );
+
+ if (USE_DATABASE_EMULATOR) {
+ FirebaseDatabase.instance.useDatabaseEmulator(emulatorHost, emulatorPort);
+ }
+
+ runApp(
+ const MaterialApp(
+ title: 'Flutter Database Example',
+ home: MyHomePage(),
+ ),
+ );
+}
+
+class MyHomePage extends StatefulWidget {
+ const MyHomePage({Key? key}) : super(key: key);
+
+ @override
+ _MyHomePageState createState() => _MyHomePageState();
+}
+
+class _MyHomePageState extends State {
+ int _counter = 0;
+ late DatabaseReference _counterRef;
+ late DatabaseReference _messagesRef;
+ late StreamSubscription _counterSubscription;
+ late StreamSubscription _messagesSubscription;
+ bool _anchorToBottom = false;
+
+ String _kTestKey = 'Hello';
+ String _kTestValue = 'world!';
+ FirebaseException? _error;
+ bool initialized = false;
+
+ @override
+ void initState() {
+ init();
+ super.initState();
+ }
+
+ Future init() async {
+ _counterRef = FirebaseDatabase.instance.ref('counter');
+
+ final database = FirebaseDatabase.instance;
+
+ _messagesRef = database.ref('messages');
+
+ database.setLoggingEnabled(false);
+
+ if (!kIsWeb) {
+ database.setPersistenceEnabled(true);
+ database.setPersistenceCacheSizeBytes(10000000);
+ }
+
+ if (!kIsWeb) {
+ await _counterRef.keepSynced(true);
+ }
+
+ setState(() {
+ initialized = true;
+ });
+
+ try {
+ final counterSnapshot = await _counterRef.get();
+
+ print(
+ 'Connected to directly configured database and read '
+ '${counterSnapshot.value}',
+ );
+ } catch (err) {
+ print(err);
+ }
+
+ _counterSubscription = _counterRef.onValue.listen(
+ (DatabaseEvent event) {
+ setState(() {
+ _error = null;
+ _counter = (event.snapshot.value ?? 0) as int;
+ });
+ },
+ onError: (Object o) {
+ final error = o as FirebaseException;
+ setState(() {
+ _error = error;
+ });
+ },
+ );
+
+ final messagesQuery = _messagesRef.limitToLast(10);
+
+ _messagesSubscription = messagesQuery.onChildAdded.listen(
+ (DatabaseEvent event) {
+ print('Child added: ${event.snapshot.value}');
+ },
+ onError: (Object o) {
+ final error = o as FirebaseException;
+ print('Error: ${error.code} ${error.message}');
+ },
+ );
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+ _messagesSubscription.cancel();
+ _counterSubscription.cancel();
+ }
+
+ Future _increment() async {
+ await _counterRef.set(ServerValue.increment(1));
+
+ await _messagesRef
+ .push()
+ .set({_kTestKey: '$_kTestValue $_counter'});
+ }
+
+ Future _incrementAsTransaction() async {
+ try {
+ final transactionResult = await _counterRef.runTransaction((mutableData) {
+ return Transaction.success((mutableData as int? ?? 0) + 1);
+ });
+
+ if (transactionResult.committed) {
+ final newMessageRef = _messagesRef.push();
+ await newMessageRef.set({
+ _kTestKey: '$_kTestValue ${transactionResult.snapshot.value}'
+ });
+ }
+ } on FirebaseException catch (e) {
+ print(e.message);
+ }
+ }
+
+ Future _deleteMessage(DataSnapshot snapshot) async {
+ final messageRef = _messagesRef.child(snapshot.key!);
+ await messageRef.remove();
+ }
+
+ void _setAnchorToBottom(bool? value) {
+ if (value == null) {
+ return;
+ }
+
+ setState(() {
+ _anchorToBottom = value;
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ if (!initialized) return Container();
+
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text('Flutter Database Example'),
+ ),
+ body: Column(
+ children: [
+ Flexible(
+ child: Center(
+ child: _error == null
+ ? Text(
+ 'Button tapped $_counter time${_counter == 1 ? '' : 's'}.\n\n'
+ 'This includes all devices, ever.',
+ )
+ : Text(
+ 'Error retrieving button tap count:\n${_error!.message}',
+ ),
+ ),
+ ),
+ ElevatedButton(
+ onPressed: _incrementAsTransaction,
+ child: const Text('Increment as transaction'),
+ ),
+ ListTile(
+ leading: Checkbox(
+ onChanged: _setAnchorToBottom,
+ value: _anchorToBottom,
+ ),
+ title: const Text('Anchor to bottom'),
+ ),
+ Flexible(
+ child: FirebaseAnimatedList(
+ key: ValueKey(_anchorToBottom),
+ query: _messagesRef,
+ reverse: _anchorToBottom,
+ itemBuilder: (context, snapshot, animation, index) {
+ return SizeTransition(
+ sizeFactor: animation,
+ child: ListTile(
+ trailing: IconButton(
+ onPressed: () => _deleteMessage(snapshot),
+ icon: const Icon(Icons.delete),
+ ),
+ title: Text('$index: ${snapshot.value.toString()}'),
+ ),
+ );
+ },
+ ),
+ ),
+ ],
+ ),
+ floatingActionButton: FloatingActionButton(
+ onPressed: _increment,
+ tooltip: 'Increment',
+ child: const Icon(Icons.add),
+ ),
+ );
+ }
+}
diff --git a/packages/firebase_database/example/pubspec.yaml b/packages/firebase_database/example/pubspec.yaml
new file mode 100644
index 0000000..5db0b4e
--- /dev/null
+++ b/packages/firebase_database/example/pubspec.yaml
@@ -0,0 +1,28 @@
+name: tests
+description: A test app for firebase database plugin (e2e).
+
+environment:
+ sdk: ">=2.18.0 <4.0.0"
+
+dependencies:
+ firebase_core: 2.4.1
+ firebase_core_tizen: ^1.0.0
+ firebase_database: 10.0.9
+ firebase_database_tizen:
+ path: ..
+ flutter:
+ sdk: flutter
+
+dependency_overrides:
+ firebase_core_tizen:
+ path: ../../firebase_core
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+ integration_test:
+ sdk: flutter
+ integration_test_tizen: ^2.0.1
+
+flutter:
+ uses-material-design: true
diff --git a/packages/firebase_database/example/test_driver/integration_test.dart b/packages/firebase_database/example/test_driver/integration_test.dart
new file mode 100644
index 0000000..f1ac26f
--- /dev/null
+++ b/packages/firebase_database/example/test_driver/integration_test.dart
@@ -0,0 +1,7 @@
+// Copyright 2022, the Chromium project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:integration_test/integration_test_driver.dart';
+
+Future main() => integrationDriver();
diff --git a/packages/firebase_database/example/tizen/.gitignore b/packages/firebase_database/example/tizen/.gitignore
new file mode 100644
index 0000000..750f3af
--- /dev/null
+++ b/packages/firebase_database/example/tizen/.gitignore
@@ -0,0 +1,5 @@
+flutter/
+.vs/
+*.user
+bin/
+obj/
diff --git a/packages/firebase_database/example/tizen/App.cs b/packages/firebase_database/example/tizen/App.cs
new file mode 100644
index 0000000..6dd4a63
--- /dev/null
+++ b/packages/firebase_database/example/tizen/App.cs
@@ -0,0 +1,20 @@
+using Tizen.Flutter.Embedding;
+
+namespace Runner
+{
+ public class App : FlutterApplication
+ {
+ protected override void OnCreate()
+ {
+ base.OnCreate();
+
+ GeneratedPluginRegistrant.RegisterPlugins(this);
+ }
+
+ static void Main(string[] args)
+ {
+ var app = new App();
+ app.Run(args);
+ }
+ }
+}
diff --git a/packages/firebase_database/example/tizen/Runner.csproj b/packages/firebase_database/example/tizen/Runner.csproj
new file mode 100644
index 0000000..f4e369d
--- /dev/null
+++ b/packages/firebase_database/example/tizen/Runner.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ tizen40
+
+
+
+
+
+
+
+
+
+ %(RecursiveDir)
+
+
+
+
diff --git a/packages/firebase_database/example/tizen/shared/res/ic_launcher.png b/packages/firebase_database/example/tizen/shared/res/ic_launcher.png
new file mode 100644
index 0000000..4d6372e
Binary files /dev/null and b/packages/firebase_database/example/tizen/shared/res/ic_launcher.png differ
diff --git a/packages/firebase_database/example/tizen/tizen-manifest.xml b/packages/firebase_database/example/tizen/tizen-manifest.xml
new file mode 100644
index 0000000..b912296
--- /dev/null
+++ b/packages/firebase_database/example/tizen/tizen-manifest.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+ ic_launcher.png
+
+
+
+ T-INFOLINK2021-1000
+
+
+ http://tizen.org/privilege/internet
+
+
+
diff --git a/packages/firebase_database/pubspec.yaml b/packages/firebase_database/pubspec.yaml
new file mode 100644
index 0000000..6000f95
--- /dev/null
+++ b/packages/firebase_database/pubspec.yaml
@@ -0,0 +1,32 @@
+name: firebase_database_tizen
+description: The Firebase Database implementation for Tizen.
+version: 0.1.0
+publish_to: 'none'
+
+environment:
+ sdk: ">=2.18.0 <4.0.0"
+ flutter: ">=3.3.0"
+
+dependencies:
+ firebase_core_tizen: ^1.0.0
+ firebase_database: 10.0.9
+ firebase_database_platform_interface: 0.2.2+17
+ flutter:
+ sdk: flutter
+
+dependency_overrides:
+ firebase_core_tizen:
+ path: ../firebase_core
+
+dev_dependencies:
+ flutter_lints: ^2.0.0
+ flutter_test:
+ sdk: flutter
+
+flutter:
+ plugin:
+ implements: firebase_database
+ platforms:
+ tizen:
+ pluginClass: FirebaseDatabaseTizenPlugin
+ fileName: firebase_database_tizen_plugin.h
diff --git a/packages/firebase_database/tizen/.gitignore b/packages/firebase_database/tizen/.gitignore
new file mode 100644
index 0000000..a2a7d62
--- /dev/null
+++ b/packages/firebase_database/tizen/.gitignore
@@ -0,0 +1,5 @@
+.cproject
+.sign
+crash-info/
+Debug/
+Release/
diff --git a/packages/firebase_database/tizen/build_def.prop b/packages/firebase_database/tizen/build_def.prop
new file mode 100644
index 0000000..64d7f61
--- /dev/null
+++ b/packages/firebase_database/tizen/build_def.prop
@@ -0,0 +1,2 @@
+PREBUILD_COMMAND = ./tar_url.sh \
+ https://github.com/daeye0n/gooddaytocode/archive/refs/tags/v10.4.0-draft-4.tar.gz
diff --git a/packages/firebase_database/tizen/dep/conversion.cc b/packages/firebase_database/tizen/dep/conversion.cc
new file mode 100644
index 0000000..44d0035
--- /dev/null
+++ b/packages/firebase_database/tizen/dep/conversion.cc
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2023-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common/conversion.h"
+
+#include
+
+#include "common/trace.h" // for UNIMPLEMENTED and FATAL
+#include "common/utils.h"
+
+using firebase::Variant;
+using flutter::EncodableList;
+using flutter::EncodableMap;
+using flutter::EncodableValue;
+
+Variant Conversion::ToFirebaseVariant(const EncodableValue& encodable_value) {
+ switch (encodable_value.index()) {
+ case 0: // std::monostate
+ return Variant();
+ case 1: // bool
+ return Variant(std::get(encodable_value));
+ case 2: // int32_t
+ return Variant(std::get(encodable_value));
+ case 3: // int64_t
+ return Variant(std::get(encodable_value));
+ case 4: // double
+ return Variant(std::get(encodable_value));
+ case 5: // std::string
+ return Variant(std::get(encodable_value));
+ case 6: // std::vector
+ return Variant(std::get>(encodable_value));
+ case 7: // std::vector
+ return Variant(std::get>(encodable_value));
+ case 8: // std::vector
+ return Variant(std::get>(encodable_value));
+ case 9: // std::vector
+ return Variant(std::get>(encodable_value));
+ case 10: // EncodableList
+ return Conversion::ToFirebaseVariant(
+ std::get(encodable_value));
+ case 11: // EncodableMap
+ return Conversion::ToFirebaseVariant(
+ std::get(encodable_value));
+ case 12: // CustomEncodableValue
+ UNIMPLEMENTED("Unknown to handle this");
+ return Variant();
+ case 13: // std::vector
+ return Variant(std::get>(encodable_value));
+ default:
+ FATAL("Invalid EncodableValue type");
+ }
+ return Variant();
+}
+
+Variant Conversion::ToFirebaseVariant(const EncodableList& encodable_list) {
+ std::vector variant_list;
+ for (const EncodableValue& encodable_value : encodable_list) {
+ variant_list.push_back(Conversion::ToFirebaseVariant(encodable_value));
+ }
+ return Variant(variant_list);
+}
+
+Variant Conversion::ToFirebaseVariant(const EncodableMap& encodable_map) {
+ std::map variant_map;
+ for (const auto& [key, value] : encodable_map) {
+ variant_map.emplace(Conversion::ToFirebaseVariant(key),
+ Conversion::ToFirebaseVariant(value));
+ }
+ return Variant(variant_map);
+}
+
+Variant Conversion::ToFirebaseVariant(const EncodableMap* map,
+ const char* key) {
+ return Conversion::ToFirebaseVariant(GetEncodableValue(map, key));
+}
+
+EncodableValue Conversion::ToEncodableValue(const Variant& v) {
+ switch (v.type()) {
+ case Variant::kTypeNull:
+ return EncodableValue(std::monostate());
+ case Variant::kTypeInt64:
+ return EncodableValue(v.int64_value());
+ case Variant::kTypeDouble:
+ return EncodableValue(v.double_value());
+ case Variant::kTypeBool:
+ return EncodableValue(v.bool_value());
+ case Variant::kTypeStaticString:
+ return EncodableValue(std::string(v.string_value()));
+ case Variant::kTypeMutableString:
+ return EncodableValue(v.mutable_string());
+ case Variant::kTypeVector: {
+ EncodableList list;
+ for (const auto& e : v.vector()) {
+ list.push_back(ToEncodableValue(e));
+ }
+ return EncodableValue(list);
+ }
+ case Variant::kTypeMap: {
+ EncodableMap map;
+ for (const auto& [key, value] : v.map()) {
+ map[ToEncodableValue(key)] = ToEncodableValue(value);
+ }
+ return EncodableValue(map);
+ }
+ default:
+ FATAL("Unsupported Variant type");
+ }
+ return EncodableValue();
+}
diff --git a/packages/firebase_database/tizen/dep/include/common/conversion.h b/packages/firebase_database/tizen/dep/include/common/conversion.h
new file mode 100644
index 0000000..10a2507
--- /dev/null
+++ b/packages/firebase_database/tizen/dep/include/common/conversion.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2023-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include
+#include
+
+class Conversion {
+ public:
+ static firebase::Variant ToFirebaseVariant(const flutter::EncodableValue& v);
+ static firebase::Variant ToFirebaseVariant(const flutter::EncodableList& l);
+ static firebase::Variant ToFirebaseVariant(const flutter::EncodableMap& m);
+ static firebase::Variant ToFirebaseVariant(const flutter::EncodableMap* m,
+ const char* key);
+ static flutter::EncodableValue ToEncodableValue(const firebase::Variant& v);
+};
diff --git a/packages/firebase_database/tizen/dep/include/common/logger.h b/packages/firebase_database/tizen/dep/include/common/logger.h
new file mode 100644
index 0000000..95d6b62
--- /dev/null
+++ b/packages/firebase_database/tizen/dep/include/common/logger.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2022-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+class LogOption {
+ public:
+ static bool isEnabled(const std::string& pattern = "");
+ static void setExternalIsEnabled(std::function);
+
+ private:
+ static std::function externalIsEnabled;
+};
+
+class Logger {
+ public:
+ class Header {
+ protected:
+ virtual void writeHeader(std::stringstream&) = 0;
+
+ private:
+ void write(std::stringstream& stream);
+ friend class Logger;
+ };
+
+ class Output {
+ public:
+ virtual ~Output() = default;
+ virtual void flush(std::stringstream& ss) = 0;
+ };
+
+ Logger(std::shared_ptr