SQLDelight: [SQLITE_ERROR] SQL error or missing database (table already exists) - android-jetpack-compose

I am trying to build a small POC with JetpackCompose Desktop and SQLDelight. I want that the data is persisted even after the application is restarted (not only in memory as all the tutorial examples I encountered show), so I tried this:
// ArticlesLocalDataSource.kt
class ArticlesLocalDataSource {
private val database: TestDb
init {
val driver: SqlDriver = JdbcSqliteDriver(url = "jdbc:sqlite:database.db")
TestDb.Schema.create(driver)
database = TestDb(driver)
}
// ...
}
When I run the application for the first time this works, i.e: a database.db file in the project root is created and the data is stored successfully.
However, when I try to run the application a second time, then it crashes immediately with:
Exception in thread "main" org.sqlite.SQLiteException: [SQLITE_ERROR] SQL error or missing database (table ArticleEntity already exists)
at org.sqlite.core.DB.newSQLException(DB.java:1012)
at org.sqlite.core.DB.newSQLException(DB.java:1024)
at org.sqlite.core.DB.throwex(DB.java:989)
at org.sqlite.core.NativeDB.prepare_utf8(Native Method)
at org.sqlite.core.NativeDB.prepare(NativeDB.java:134)
at org.sqlite.core.DB.prepare(DB.java:257)
at org.sqlite.core.CorePreparedStatement.<init>(CorePreparedStatement.java:45)
at org.sqlite.jdbc3.JDBC3PreparedStatement.<init>(JDBC3PreparedStatement.java:30)
at org.sqlite.jdbc4.JDBC4PreparedStatement.<init>(JDBC4PreparedStatement.java:25)
at org.sqlite.jdbc4.JDBC4Connection.prepareStatement(JDBC4Connection.java:35)
at org.sqlite.jdbc3.JDBC3Connection.prepareStatement(JDBC3Connection.java:241)
at org.sqlite.jdbc3.JDBC3Connection.prepareStatement(JDBC3Connection.java:205)
at com.squareup.sqldelight.sqlite.driver.JdbcDriver.execute(JdbcDriver.kt:109)
at com.squareup.sqldelight.db.SqlDriver$DefaultImpls.execute$default(SqlDriver.kt:52)
at com.vgrec.TestPlus.TestDbImpl$Schema.create(TestDbImpl.kt:33)
at com.vgrec.data.local.ArticlesLocalDataSource.<init>(ArticlesLocalDataSource.kt:20)
I understand that it's crashing because there's an attempt to create the database again, but the database already exists. What is not clear to me, is how do I connect to the DB if a DB already exists?
For completeness, here's the build file:
// build.gradle
plugins {
kotlin("jvm") version "1.6.10"
id("org.jetbrains.compose") version "1.1.0"
// ...
id("com.squareup.sqldelight") version "1.5.3"
}
sqldelight {
database("TestDb") {
packageName = "com.test"
}
}
dependencies {
implementation(compose.desktop.currentOs)
// ..
implementation("com.squareup.sqldelight:sqlite-driver:1.5.4")
implementation("com.squareup.sqldelight:coroutines-extensions-jvm:1.5.4")
}

OK, so in the end I decided to just check if the database file exists and invoke the creation only if it does not exist.
Something like this:
init {
val driver: SqlDriver = JdbcSqliteDriver("jdbc:sqlite:database.db")
if (!File("database.db").exists()) {
TestDb.Schema.create(driver)
}
// ...
}
From first glance this seems to work as expected, but I am not sure this is the recommended approach as I am very new to SQLDelight, so other suggestions are welcome.

Related

Resolve mx records for a domain using dnsjava in kubernetes/ docker

I'm trying to resolve mx records in a kubernetes pod.
The dnsjava library works when tested on mac and ubuntu outside of a container but returns an empty array once deployed.
What needs to be available in k8s or the docker image for this to work?
See https://github.com/dnsjava/dnsjava
EDIT 1
Record[] records;
try {
records = new Lookup(mailDomain, Type.MX).run();
} catch (TextParseException e) {
throw new IllegalStateException(e);
}
if (records != null && records.length > 0) {
for (final Record record : records) {
MXRecord mx = (MXRecord) record;
//do something with mx...
}
} else {
log.warn("Failed to determine MX record for {}", mailDomain);
}
The log.warn is always executed in K8s. The docker image is openjdk:11-jdk-slim i.e. it's Debian. I just tested on Debian outside of Docker and it worked as well.
In the end I couldn't get dnsjava to work in docker/k8s.
I used JNDI directly, following https://stackoverflow.com/a/16448180/400048
this works without any issues exactly as given in that answer.

Execution failed for task ':buildDB2BotcImage'

System Info : Windows 10 Enterprise
Gradle Version 4.3.1
Docker Version 17.10.0-ce, build f4ffd25
I am getting an issue while doing gradle.build, Error I am getting
Unrecognized field "identitytoken" (class com.github.dockerjava.api.model.AuthConfig), not marked as ignorable (6 known properties: "serveraddress", "username", "auth", "password", "email", "registrytoken"])
at [Source: N/A; line: -1, column: -1] (through reference chain: java.util.LinkedHashMap["auths"]->java.util.LinkedHashMap["registry.au-syd.bluemix.net"]->com.github.dockerjava.api.model.AuthConfig["identitytoken"])
I have done some research and found this https://github.com/bmuschko/gradle-docker-plugin/issues/310 , and done some changes in my build.gradle but still i am getting this error.
The changes I have done in one of the part of build.gradle file :
Previously:
docker {
if (System.properties['os.name'].toLowerCase().contains('windows')) {
url = 'tcp://localhost:2376'
certPath = new File(System.properties['user.home'], '.docker/machine/certs')
}
registryCredentials {
url = 'https://maxrep01.swg.usma.ibm.com/'
username = 'username'
password = 'secret'
}
}
Changed:
docker {
if (System.properties['os.name'].toLowerCase().contains('windows')) {
if (new File("\\\\.\\pipe\\docker_engine").exists()) {
url = 'npipe:////./pipe/docker_engine'
}
else {
url = 'tcp://localhost:2376'
}
certPath = new File(System.properties['user.home'], '.docker/machine/certs')
}
registryCredentials {
url = 'https://maxrep01.swg.usma.ibm.com/'
username = 'username'
password = 'secret'
}
}
This is the only helpful link I am getting, but I am unable to get what is the issue is, my understanding is it is something related to windows 10, but as per the link the changes i have done should resolve the issue.
I am not sure what is wrong here?
Your problem is most likely related to Issue #921 of the docker-java project.
Hello, we got the issue, using latest version of "docker-java" while trying to load and parse DOCKER configuration file ("$HOME/.docker/config.json").
It doesn't accept the field 'identitytoken'. I have noticed that you have 'registrytoken' field, which have been used since DOCKER API v1.22 version for the same purpose. I checked documentation, it was renamed there into --> 'identitytoken' just in the next DOCKER API v1.23 version.
If waiting for a next docker-java version is not acceptable, it might help to tweak config.json to suit your needs.

Grails 3.3 execute H2 script command

I'm running a small, trivial Grails 3.3.0 application using a H2 file based database. For simple backup reasons I would like to dump the current database state to a file using the H2 specific SCRIPT command:
SCRIPT TO /path/to/backup/dir/tempoDb.sql;
Currently I am trying to execute the native SQL command like this.
User.withSession { session ->
NativeSQLQuerySpecification nativeSQLQuerySpecification = new NativeSQLQuerySpecification("SCRIPT TO /path/to/backup/dir/tempoDb.sql;", null, null)
session.executeNativeUpdate(nativeSQLQuerySpecification, new QueryParameters())
}
but this does not work.
You can autowire the dataSource and try to run your sql query using the connection obtained from datasource Without going through Hibernate. The dataSource bean is registered in the Grails Spring context and it is an instance of javax.sql.DataSource.
Here is an example of a Grails service that backup the current H2 database to the file system.
#ReadOnly
class BackupService {
DataSource dataSource
def backup() {
def sql = "SCRIPT DROP TO '${System.properties['java.io.tmpdir']}/backup.sql'"
Statement statement = dataSource.connection.createStatement()
boolean result = statement.execute(sql)
}
}

Copying default external configuration on first run of Grails web app

In our Grails web applications, we'd like to use external configuration files so that we can change the configuration without releasing a new version. We'd also like these files to be outside of the application directory so that they stay unchanged during continuous integration.
The last thing we need to do is to make sure the external configuration files exist. If they don't, then we'd like to create them, fill them with predefined content (production environment defaults) and then use them as if they existed before. This allows any administrator to change settings of the application without detailed knowledge of the options actually available.
For this purpose, there's a couple of files within web-app/WEB-INF/conf ready to be copied to the external configuration location upon the first run of the application.
So far so good. But we need to do this before the application is initialized so that production-related modifications to data sources definitions are taken into account.
I can do the copy-and-load operation inside the Config.groovy file, but I don't know the absolute location of the WEB-INF/conf directory at the moment.
How can I get the location during this early phase of initialization? Is there any other solution to the problem?
There is a best practice for this.
In general, never write to the folder where the application is deployed. You have no control over it. The next rollout will remove everything you wrote there.
Instead, leverage the builtin configuration capabilities the real pro's use (Spring and/or JPA).
JNDI is the norm for looking up resources like databases, files and URL's.
Operations will have to configure JNDI, but they appreciate the attention.
They also need an initial set of configuration files, and be prepared to make changes at times as required by the development team.
As always, all configuration files should be in your source code repo.
I finally managed to solve this myself by using the Java's ability to locate resources placed on the classpath.
I took the .groovy files later to be copied outside, placed them into the grails-app/conf directory (which is on the classpath) and appended a suffix to their name so that they wouldn't get compiled upon packaging the application. So now I have *Config.groovy files containing configuration defaults (for all environments) and *Config.groovy.production files containing defaults for production environment (overriding the precompiled defaults).
Now - Config.groovy starts like this:
grails.config.defaults.locations = [ EmailConfig, AccessConfig, LogConfig, SecurityConfig ]
environments {
production {
grails.config.locations = ConfigUtils.getExternalConfigFiles(
'.production',
"${userHome}${File.separator}.config${File.separator}${appName}",
'AccessConfig.groovy',
'Config.groovy',
'DataSource.groovy',
'EmailConfig.groovy',
'LogConfig.groovy',
'SecurityConfig.groovy'
)
}
}
Then the ConfigUtils class:
public class ConfigUtils {
// Log4j may not be initialized yet
private static final Logger LOG = Logger.getGlobal()
public static def getExternalConfigFiles(final String defaultSuffix, final String externalConfigFilesLocation, final String... externalConfigFiles) {
final def externalConfigFilesDir = new File(externalConfigFilesLocation)
LOG.info "Loading configuration from ${externalConfigFilesDir}"
if (!externalConfigFilesDir.exists()) {
LOG.warning "${externalConfigFilesDir} not found. Creating..."
try {
externalConfigFilesDir.mkdirs()
} catch (e) {
LOG.severe "Failed to create external configuration storage. Default configuration will be used."
e.printStackTrace()
return []
}
}
final def cl = ConfigUtils.class.getClassLoader()
def result = []
externalConfigFiles.each {
final def file = new File(externalConfigFilesDir, it)
if (file.exists()) {
result << file.toURI().toURL()
return
}
final def error = false
final def defaultFileURL = cl.getResource(it + defaultSuffix)
final def defaultFile
if (defaultFileURL) {
defaultFile = new File(defaultFileURL.toURI())
error = !defaultFile.exists();
} else {
error = true
}
if (error) {
LOG.severe "Neither of ${file} or ${defaultFile} exists. Skipping..."
return
}
LOG.warning "${file} does not exist. Copying ${defaultFile} -> ${file}..."
try {
FileUtils.copyFile(defaultFile, file)
} catch (e) {
LOG.severe "Couldn't copy ${defaultFile} -> ${file}. Skipping..."
e.printStackTrace()
return
}
result << file.toURI().toURL()
}
return result
}
}

Grails: importing plugin classes to _Events.groovy

I've created a Grails plugin which adds a custom test type class (extending GrailsTestTypeSupport) and custom test result class (extending GrailsTestTypeResult) to support a custom test type that I run during the other phase of the test-app script. Testing this on my local machine has gone swimmingly but...
When I packaged the plugin to use in my app, the tests are blowing up on our CI server (Jenkins). Here's the error that Jenkins is spitting out:
unable to resolve class CustomTestResult # line 58, column 9.
new CustomTestResult(tests.size() - failed, failed)
It appears that I cannot simply import these classes into _Events.groovy, and the classes are not otherwise on the classpath. But I'll be damned if I can figure out how to get them onto the classpath. Here's what I have so far (in _Events.groovy):
import java.lang.reflect.Constructor
eventAllTestsStart = {
if (!otherTests) otherTests = []
loadCustomTestResult()
otherTests << createCustomTestType()
}
private def createCustomTestType(String name = 'js', String relativeSourcePath = 'js') {
ClassLoader parent = getClass().getClassLoader()
GroovyClassLoader loader = new GroovyClassLoader(parent)
Class customTestTypeClass = loader.parseClass(new File("${customTestPluginDir}/src/groovy/custom/test/CustomTestType.groovy"))
Constructor customTestTypeConstructor = customTestTypeClass.getConstructor(String, String)
def customTestType = customTestTypeConstructor.newInstance(name, relativeSourcePath)
customTestType
}
private def loadCustomTestResult() {
ClassLoader parent = getClass().getClassLoader()
GroovyClassLoader loader = new GroovyClassLoader(parent)
Class customTestResultClass = loader.parseClass(new File("${customTestPluginDir}/src/groovy/custom/test/CustomTestResult.groovy"))
}
Currently: CustomTestResult is only referenced from within CustomTestType. As far as I can tell, _Events.groovy is loading CustomTestType but it is failing because it then insists that CustomTestResult is not on the classpath.
Putting aside for a moment that it seems crazy that there's this much overhead to get plugin-furnished classes onto the classpath for the test cycle to begin with... I'm not quite sure where I've gotten tripped up. Any help or pointers would be greatly appreciated.
Have you tried simply loading the class in question via the ClassLoader that is accessible via the classLoader variable in _Events.groovy?
Class customTestTypeClass = classLoader.loadClass('custom.test.CustomTestType')
// use nice groovy overloading of Class.newInstance
return customTestTypeClass.newInstance(name, relativeSourcePath)
You should be late enough in the process at eventAllTestsStart for this to be valid.
#Ian Roberts' answer got me pointed in roughly the right direction, and combined with the _Events.groovy script from this grails-cucumber plugin, I managed to come through with this solution:
First, _Events.groovy became this:
eventAllTestsStart = { if (!otherTests) otherTests = [] }
eventTestPhasesStart = { phases ->
if (!phases.contains('other')) { return }
// classLoader.loadClass business per Ian Roberts:
otherTests << classLoader.loadClass('custom.test.CustomTestType').newInstance('js', 'js')
}
Which is far more readable than where I was at the start of this thread. But: I was in roughly the same position: my ClassNotFoundException moved from being thrown in _Events.groovy to being thrown from within CustomTestType when it tried to create an instance of custom.test. CustomTestResult. So within CustomTestType, I added the following method:
private GrailsTestTypeResult createResult(passed, failed) {
try {
return new customTestResult(passed, failed)
} catch(ClassNotFoundException cnf) {
Class customTestResult = buildBinding.classLoader.loadClass('custom.test.CustomTestResult')
return customTestResult.newInstance(passed, failed)
}
}
So Ian was right, inasmuch as classLoader came to the rescue -- I just wound up needing its magic in two places.

Resources