Skip to content

Commit 90f36be

Browse files
committed
firebase-dataconnect minimal demo app added
1 parent 801bf4d commit 90f36be

File tree

24 files changed

+1657
-0
lines changed

24 files changed

+1657
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.gradle/
2+
.idea/
3+
.kotlin/
4+
5+
build/
6+
local.properties
7+
8+
*.log
9+
*.hprof
10+
/dataConnectGeneratedSources/

firebase-dataconnect/demo/.idea/runConfigurations/spotlessApply.xml

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
2+
import java.nio.charset.StandardCharsets
3+
4+
plugins {
5+
// Use whichever versions of these dependencies suit your application.
6+
// The versions shown here were the latest versions as of December 03, 2024.
7+
// Note, however, that the version of kotlin("plugin.serialization") _must_,
8+
// in general, match the version of kotlin("android").
9+
id("com.android.application") version "8.7.3"
10+
id("com.google.gms.google-services") version "4.4.2"
11+
val kotlinVersion = "2.1.0"
12+
kotlin("android") version kotlinVersion
13+
kotlin("plugin.serialization") version kotlinVersion
14+
15+
// The following code in this "plugins" block can be omitted from customer
16+
// facing documentation as it is an implementation detail of this application.
17+
id("com.diffplug.spotless") version "7.0.0.BETA4"
18+
}
19+
20+
dependencies {
21+
// Use whichever versions of these dependencies suit your application.
22+
// The versions shown here were the latest versions as of December 03, 2024.
23+
implementation("com.google.firebase:firebase-dataconnect:16.0.0-beta03")
24+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
25+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0")
26+
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.3")
27+
implementation("androidx.appcompat:appcompat:1.7.0")
28+
implementation("androidx.activity:activity-ktx:1.9.3")
29+
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7")
30+
implementation("com.google.android.material:material:1.12.0")
31+
32+
// The following code in this "dependencies" block can be omitted from customer
33+
// facing documentation as it is an implementation detail of this application.
34+
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.3")
35+
implementation("io.kotest:kotest-property:5.9.1")
36+
implementation("io.kotest.extensions:kotest-property-arbs:2.1.2")
37+
}
38+
39+
// The remaining code in this file can be omitted from customer facing
40+
// documentation. It's here just to make things compile and/or configure
41+
// optional components of the build (e.g. spotless code formatting).
42+
43+
android {
44+
namespace = "com.google.firebase.dataconnect.minimaldemo"
45+
compileSdk = 35
46+
defaultConfig {
47+
minSdk = 21
48+
targetSdk = 35
49+
versionCode = 1
50+
versionName = "1.0"
51+
}
52+
compileOptions {
53+
sourceCompatibility = JavaVersion.VERSION_1_8
54+
targetCompatibility = JavaVersion.VERSION_1_8
55+
isCoreLibraryDesugaringEnabled = true
56+
}
57+
buildFeatures.viewBinding = true
58+
kotlinOptions.jvmTarget = "1.8"
59+
}
60+
61+
spotless {
62+
val ktfmtVersion = "0.53"
63+
kotlin {
64+
target("**/*.kt")
65+
targetExclude("build/")
66+
ktfmt(ktfmtVersion).googleStyle()
67+
}
68+
kotlinGradle {
69+
target("**/*.gradle.kts")
70+
targetExclude("build/")
71+
ktfmt(ktfmtVersion).googleStyle()
72+
}
73+
json {
74+
target("**/*.json")
75+
targetExclude("build/")
76+
simple().indentWithSpaces(2)
77+
}
78+
yaml {
79+
target("**/*.yaml")
80+
targetExclude("build/")
81+
jackson()
82+
.yamlFeature("INDENT_ARRAYS", true)
83+
.yamlFeature("MINIMIZE_QUOTES", true)
84+
.yamlFeature("WRITE_DOC_START_MARKER", false)
85+
}
86+
format("xml") {
87+
target("**/*.xml")
88+
targetExclude("build/")
89+
trimTrailingWhitespace()
90+
indentWithSpaces(2)
91+
endWithNewline()
92+
}
93+
}
94+
95+
abstract class DataConnectGenerateSourcesTask : DefaultTask() {
96+
97+
@get:InputDirectory abstract val inputDirectory: DirectoryProperty
98+
99+
@get:OutputDirectory abstract val outputDirectory: DirectoryProperty
100+
101+
@get:Internal abstract val nodeExecutableDirectory: DirectoryProperty
102+
103+
@get:Internal abstract val firebaseCommand: Property<String>
104+
105+
@get:Internal abstract val workDirectory: DirectoryProperty
106+
107+
@get:Inject protected abstract val execOperations: ExecOperations
108+
109+
@get:Inject protected abstract val providerFactory: ProviderFactory
110+
111+
@get:Inject protected abstract val fileSystemOperations: FileSystemOperations
112+
113+
@TaskAction
114+
fun run(inputChanges: InputChanges) {
115+
if (inputChanges.isIncremental) {
116+
val onlyLogFilesChanged =
117+
inputChanges.getFileChanges(inputDirectory).all { it.file.name.endsWith(".log") }
118+
if (onlyLogFilesChanged) {
119+
didWork = false
120+
return
121+
}
122+
}
123+
124+
val inputDirectory: File = inputDirectory.get().asFile
125+
val outputDirectory: File = outputDirectory.get().asFile
126+
val nodeExecutableDirectory: File? = nodeExecutableDirectory.orNull?.asFile
127+
val firebaseCommand: String? = firebaseCommand.orNull
128+
val workDirectory: File = workDirectory.get().asFile
129+
130+
outputDirectory.deleteRecursively()
131+
outputDirectory.mkdirs()
132+
workDirectory.deleteRecursively()
133+
workDirectory.mkdirs()
134+
135+
val newPath: String? =
136+
if (nodeExecutableDirectory === null) {
137+
null
138+
} else {
139+
val nodeExecutableDirectoryAbsolutePath = nodeExecutableDirectory.absolutePath
140+
val oldPath = providerFactory.environmentVariable("PATH").orNull
141+
if (oldPath === null) {
142+
nodeExecutableDirectoryAbsolutePath
143+
} else {
144+
nodeExecutableDirectoryAbsolutePath + File.pathSeparator + oldPath
145+
}
146+
}
147+
148+
val logFile =
149+
if (logger.isInfoEnabled) {
150+
null
151+
} else {
152+
File(workDirectory, "dataconnect.sdk.generate.log.txt")
153+
}
154+
155+
val execResult =
156+
logFile?.outputStream().use { logStream ->
157+
execOperations.runCatching {
158+
exec {
159+
commandLine(firebaseCommand ?: "firebase", "--debug", "dataconnect:sdk:generate")
160+
workingDir(inputDirectory)
161+
isIgnoreExitValue = false
162+
if (newPath !== null) {
163+
environment("PATH", newPath)
164+
}
165+
if (logStream !== null) {
166+
standardOutput = logStream
167+
errorOutput = logStream
168+
}
169+
}
170+
}
171+
}
172+
173+
execResult.onFailure { exception ->
174+
logFile?.readText(StandardCharsets.UTF_8)?.lines()?.forEach { line ->
175+
logger.warn("{}", line.trimEnd())
176+
}
177+
throw exception
178+
}
179+
}
180+
}
181+
182+
abstract class CopyDirectoryTask : DefaultTask() {
183+
184+
@get:InputDirectory abstract val srcDirectory: DirectoryProperty
185+
186+
@get:OutputDirectory abstract val destDirectory: DirectoryProperty
187+
188+
@get:Inject protected abstract val fileSystemOperations: FileSystemOperations
189+
190+
@TaskAction
191+
fun run() {
192+
val srcDirectory: File = srcDirectory.get().asFile
193+
val destDirectory: File = destDirectory.get().asFile
194+
195+
logger.info("srcDirectory: {}", srcDirectory.absolutePath)
196+
logger.info("destDirectory: {}", destDirectory.absolutePath)
197+
198+
destDirectory.deleteRecursively()
199+
destDirectory.mkdirs()
200+
201+
fileSystemOperations.copy {
202+
from(srcDirectory)
203+
into(destDirectory)
204+
}
205+
}
206+
}
207+
208+
run {
209+
val dataConnectTaskGroupName = "Firebase Data Connect Minimal App"
210+
val projectDirectory = layout.projectDirectory
211+
212+
val generateSourcesTask =
213+
tasks.register<DataConnectGenerateSourcesTask>("dataConnectGenerateSources") {
214+
group = dataConnectTaskGroupName
215+
description =
216+
"Run firebase dataconnect:sdk:generate to generate the Data Connect Kotlin SDK sources"
217+
218+
inputDirectory = projectDirectory.dir("firebase")
219+
outputDirectory = projectDirectory.dir("dataConnectGeneratedSources")
220+
221+
nodeExecutableDirectory =
222+
project.providers.gradleProperty("dataConnect.minimalApp.nodeExecutableDirectory").map {
223+
projectDirectory.dir(it)
224+
}
225+
firebaseCommand = project.providers.gradleProperty("dataConnect.minimalApp.firebaseCommand")
226+
227+
workDirectory = layout.buildDirectory.dir(name)
228+
}
229+
230+
val androidComponents = extensions.getByType<ApplicationAndroidComponentsExtension>()
231+
androidComponents.onVariants { variant ->
232+
val variantNameTitleCase = variant.name[0].uppercase() + variant.name.substring(1)
233+
val copyTaskName = "dataConnectCopy${variantNameTitleCase}GeneratedSources"
234+
val copyTask =
235+
tasks.register<CopyDirectoryTask>(copyTaskName) {
236+
group = dataConnectTaskGroupName
237+
description =
238+
"Copy the generated Data Connect Kotlin SDK sources into the " +
239+
"generated code directory for the \"${variant.name}\" variant."
240+
srcDirectory = generateSourcesTask.flatMap { it.outputDirectory }
241+
}
242+
243+
variant.sources.java!!.addGeneratedSourceDirectory(copyTask, CopyDirectoryTask::destDirectory)
244+
}
245+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"projects": {
3+
"default": "fakeproject"
4+
}
5+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/.dataconnect/
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
connectorId: ctry3q3tp6kzx
2+
generate:
3+
kotlinSdk:
4+
outputDir: ../../../dataConnectGeneratedSources
5+
package: com.google.firebase.dataconnect.minimaldemo.connector
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
mutation InsertItem(
2+
$string: String,
3+
$int: Int,
4+
$int64: Int64,
5+
$float: Float,
6+
$boolean: Boolean,
7+
$date: Date,
8+
$timestamp: Timestamp,
9+
$any: Any,
10+
) @auth(level: PUBLIC) {
11+
key: zwda6x9zyy_insert(data: {
12+
string: $string,
13+
int: $int,
14+
int64: $int64,
15+
float: $float,
16+
boolean: $boolean,
17+
date: $date,
18+
timestamp: $timestamp,
19+
any: $any,
20+
})
21+
}
22+
23+
query GetItemByKey(
24+
$key: zwda6x9zyy_Key!
25+
) @auth(level: PUBLIC) {
26+
item: zwda6x9zyy(key: $key) {
27+
string
28+
int
29+
int64
30+
float
31+
boolean
32+
date
33+
timestamp
34+
any
35+
}
36+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
specVersion: v1beta
2+
serviceId: srv3ar8skbsza
3+
location: us-central1
4+
schema:
5+
source: ./schema
6+
datasource:
7+
postgresql: null
8+
connectorDirs:
9+
- ./connector
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
type zwda6x9zyy @table {
2+
string: String
3+
int: Int
4+
int64: Int64
5+
float: Float
6+
boolean: Boolean
7+
date: Date
8+
timestamp: Timestamp
9+
any: Any
10+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"dataconnect": {"source": "dataconnect"},
3+
"emulators": {
4+
"singleProjectMode": true,
5+
"dataconnect": {"port": 9399},
6+
"ui": {"enabled": true}
7+
}
8+
}

0 commit comments

Comments
 (0)