How to setup SQLite in Kotlin? - sqlite

I'm currently writing a chat application in Kotlin and want to implement authentication, by storing hashed passwords on my server in a database.
I don't have any experience with Databases, so I chose the most simple looking one I found after about 30 minutes of google search. SQLite.
Unfortunatly there isn't any real setup guide for SQLite in Kotlin.
Could someone please write a small step by step guide on how to :
install SQLite
connect to it
use it in source code(e.g. create a table with one or two values)
all in Kotlin if possible
I'm grateful for any help!

Here's an MWE using JDBC API on Ubuntu 20.04:
sudo apt install sqlite3
SQLITE_VERSION=`sqlite3 --version | cut -d ' ' -f 1` # 3.31.1 on Ubuntu 20.04
curl -s https://get.sdkman.io | bash
sdk i java # for JDBC
sdk i maven # for JDBC interface to SQLite (see later)
sdk i kotlin 1.4.10 # later versions are currently affected by:
# https://youtrack.jetbrains.com/issue/KT-43520
cat > demo.main.kts <<EOF
#!/usr/bin/env kotlin
# uses maven to install the dependency from maven central:
# reference: https://github.com/Kotlin/KEEP/blob/master/proposals/scripting-support.md#kotlin-main-kts
#file:DependsOn("org.xerial:sqlite-jdbc:$SQLITE_VERSION")
import java.sql.DriverManager
import java.sql.Connection
import java.sql.Statement
import java.sql.ResultSet
# creates or connects to database.sqlite3 file in the current directory:
var connection = DriverManager.getConnection("jdbc:sqlite:database.sqlite3")
var statement = connection.createStatement()
statement.executeUpdate("drop table if exists people")
statement.executeUpdate("create table people (id integer, name string)")
statement.executeUpdate("insert into people values(1, 'leo')")
statement.executeUpdate("insert into people values(2, 'yui')")
var resultSet = statement.executeQuery("select * from people")
while ( resultSet.next() ) {
println( "id = " + resultSet.getInt("id") )
println( "name = " + resultSet.getString("name") )
println()
}
connection.close()
EOF
chmod +x demo.main.kts
./demo.main.kts

Sqlite doesn't work with a client-server model. The datas are stored in file of your choice, so there is no installation to do.
Maybe you can look Exposed. It is a kotlin library for sql database (sqlite included).
There is a documentation here.
You just need to add the 'org.jetbrains.exposed:exposed' depedency to gradle or maven (+ the jdbc library depedency, for SQLlite it is 'org.xerial:sqlite-jdbc').

import com.sun.net.httpserver.HttpServer
import java.io.PrintWriter
import java.net.InetSocketAddress
import java.sql.* // Connection, DriverManager, SQLException
import java.util.Properties
/**
https://www.tutorialkart.com/kotlin/connect-to-mysql-database-from-kotlin-using-jdbc/
$ wget https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.27.2.1/sqlite-jdbc-3.27.2.1.jar
$ kotlinc sqws.kt; kotlin -cp ".:./sqlite-jdbc-3.27.2.1.jar" SqwsKt
Minimal embedded HTTP server in Kotlin using Java built in HttpServer
**/
fun main(args: Array<String>) {
val conn = DriverManager.getConnection( "jdbc:sqlite:./sampledb.db")
var stmt: Statement? = null
var resultset: ResultSet? = null
try {
stmt = conn.createStatement()
resultset = stmt!!.executeQuery("SELECT * FROM items;")
if (stmt.execute("SELECT * FROM items;")) {
resultset = stmt.resultSet
}
} catch (ex: SQLException) {
// handle any errors
ex.printStackTrace()
}
HttpServer.create(InetSocketAddress(8080), 0).apply {
println("browse http://localhost:8080/hello")
createContext("/hello") { http ->
http.responseHeaders.add("Content-type", "text/plain")
http.sendResponseHeaders(200, 0);
PrintWriter(http.responseBody).use { out ->
out.println( "ok")
while (resultset!!.next()) {
out.println(resultset.getString("name"))
}
}
}
start()
}
}
Please check the full documentation on Github.

As soon as you mention server then you are perhaps looking in the wrong direction. SQLite is intended as an embedded database, each device having it's unique database. Synchronisation between server and clients would have to be written and can be problematic, whilst there are many RDBMS's that cater for better for client-server solutions.
Have a look at Appropriate Uses For SQLite.

Related

Automating component deletion in Nexus 3

I am attempting to delete some components in a repository via the nexus 3 api
I have followed the instructions in the following question
Using the Nexus3 API how do I get a list of artifacts in a repository
and have modified it as follows to delete an artifact
import groovy.json.JsonOutput
import org.sonatype.nexus.repository.storage.Component
import org.sonatype.nexus.repository.storage.Query
import org.sonatype.nexus.repository.storage.StorageFacet
def repoName = "eddie-test"
def startDate = "2016/01/01"
def artifactName = "you-artifact-name"
def artifactVersion = "1.0.6"
log.info(" Attempting to delete for repository: ${repoName} as of startDate: ${startDate}")
def repo = repository.repositoryManager.get(repoName)
StorageFacet storageFacet = repo.facet(StorageFacet)
def tx = storageFacet.txSupplier().get()
tx.begin()
// build a query to return a list of components scoped by name and version
Iterable<Component> foundComponents = tx.findComponents(Query.builder().where('name = ').param(artifactName).and('version = ').param(artifactVersion).build(), [repo])
// extra logic for validation goes here
if (foundComponents.size() == 1) {
tx.deleteComponent(foundComponents[0])
}
tx.commit()
log.info("done")
however when I interrogate the maven-metadata.xml in
http://localhost:32769/repository/eddie-test/com/company/you-artifact-name/maven-metadata.xml
the version is still listed.
i.e.
<metadata>
<groupId>com.company</groupId>
<artifactId>you-artifact-name</artifactId>
<versioning>
<release>1.0.7</release>
<versions>
<version>1.0.6</version>
<version>1.0.7</version>
</versions>
<lastUpdated>20161213115754</lastUpdated>
</versioning>
(deleting the component via the delete component button in the ui, updates the maven-metadata.xml as expected)
So is there a way to make sure that the file is updated when deleting via the API?
After running this, you can run the Rebuild Maven repository metadata Scheduled Task and that will accomplish what you aim to achieve.
There is currently no Public API for calling that task. If you want, pop on over to https://issues.sonatype.org/browse/NEXUS and make an issue for that :)

DynamodbMapper python run locally

I have a code in python something like this which is using dynamodbmapper
from dynamodb_mapper.model import DynamoDBModel
class Employee(DynamoDBModel):
__table__ = u"employee"
__hash_key__ = u"emp_id"
__schema__ = {
u"emp_id": int,
u"name": unicode,
u"address": set,
}
__defaults__ = {
u"address": set([u"Konami"]),
}
I have all the credentials set on aws.
Just wrote a small python client to create a table in dynamodb using dynamodbmapper in python.
from dynamodb_mapper.model import ConnectionBorg
from influencers.data_access.Employee import Employee
conn = ConnectionBorg()
conn.create_table(Employee, 10, 10, wait_for_active=True)
I am tryinng to run this locally . I am running dynamodb locally . My question is how do i say the endpoint name for this client as http://localhost:8000. I looked at the java code and there is a cleaner way of entting endpoint on dynamodbclient. But in python i dont see it. Any help would be greatly appreciated.

groovy upload jar to nexus

I have some jar file (custom) which I need to publish to Sonatype Nexus repository from Groovy script.
I have jar located in some path on machine where Groovy script works (for instance: c:\temp\module.jar).
My Nexus repo url is http://:/nexus/content/repositories/
On this repo I have folder structure like: folder1->folder2->folder3
During publishing my jar I need to create in folder3:
New directory with module's revision (my Groovy script knows this revision)
Upload jar to this directory
Create pom, md5 and sha1 files for jar uploaded
After several days of investigation I still have no idea how to create such script but this way looks very clear instead of using direct uploading.
I found http://groovy.codehaus.org/Using+Ant+Libraries+with+AntBuilder and some other stuff (stackoverflow non script solution).
I got how to create ivy.xml in my Groovy script, but I don't understand how to create build.xml and ivysetting.xml on the fly and setup whole system to work.
Could you please help to understand Groovy's way?
UPDATE:
I found that the following command works fine for me:
curl -v -F r=thirdparty -F hasPom=false -F e=jar -F g=<my_groupId> -F a=<my_artifactId> -F v=<my_artifactVersion> -F p=jar -F file=#module.jar -u admin:admin123 http://<my_nexusServer>:8081/nexus/service/local/repositories
As I understand curl perform POST request to Nexus services. Am I correct?
And now I'm trying to build HTTP POST request using Groovy HTTPBuilder.
How I should transform curl command parameters into Groovy's HTTPBuilder request?
Found a way to do this with the groovy HttpBuilder.
based on info from sonatype, and a few other sources.
This works with http-builder version 0.7.2 (not with earlier versions)
And also needs an extra dependency: 'org.apache.httpcomponents:httpmime:4.2.1'
The example also uses basic auth against nexus.
import groovyx.net.http.Method
import groovyx.net.http.ContentType;
import org.apache.http.HttpRequest
import org.apache.http.HttpRequestInterceptor
import org.apache.http.entity.mime.MultipartEntity
import org.apache.http.entity.mime.content.FileBody
import org.apache.http.entity.mime.content.StringBody
import org.apache.http.protocol.HttpContext
import groovyx.net.http.HttpResponseException;
class NexusUpload {
def uploadArtifact(Map artifact, File fileToUpload, String user, String password) {
def path = "/service/local/artifact/maven/content"
HTTPBuilder http = new HTTPBuilder("http://my-nexus.org/")
String basicAuthString = "Basic " + "$user:$password".bytes.encodeBase64().toString()
http.client.addRequestInterceptor(new HttpRequestInterceptor() {
void process(HttpRequest httpRequest, HttpContext httpContext) {
httpRequest.addHeader('Authorization', basicAuthString)
}
})
try {
http.request(Method.POST, ContentType.ANY) { req ->
uri.path = path
MultipartEntity entity = new MultipartEntity()
entity.addPart("hasPom", new StringBody("false"))
entity.addPart("file", new FileBody(fileToUpload))
entity.addPart("a", new StringBody("my-artifact-id"))
entity.addPart("g", new StringBody("my-group-id"))
entity.addPart("r", new StringBody("my-repository"))
entity.addPart("v", new StringBody("my-version"))
req.entity = entity
response.success = { resp, reader ->
if(resp.status == 201) {
println "success!"
}
}
}
} catch (HttpResponseException e) {
e.printStackTrace()
}
}
}
`
Ivy is an open source library, so, one approach would be to call the classes directly. The problem with that approach is that there are few examples on how to invoke ivy programmatically.
Since groovy has excellent support for generating XML, I favour the slightly dumber approach of creating the files I understand as an ivy user.
The following example is designed to publish files into Nexus generating both the ivy and ivysettings files:
import groovy.xml.NamespaceBuilder
import groovy.xml.MarkupBuilder
// Methods
// =======
def generateIvyFile(String fileName) {
def file = new File(fileName)
file.withWriter { writer ->
xml = new MarkupBuilder(writer)
xml."ivy-module"(version:"2.0") {
info(organisation:"org.dummy", module:"dummy")
publications() {
artifact(name:"dummy", type:"pom")
artifact(name:"dummy", type:"jar")
}
}
}
return file
}
def generateSettingsFile(String fileName) {
def file = new File(fileName)
file.withWriter { writer ->
xml = new MarkupBuilder(writer)
xml.ivysettings() {
settings(defaultResolver:"central")
credentials(host:"myrepo.com" ,realm:"Sonatype Nexus Repository Manager", username:"deployment", passwd:"deployment123")
resolvers() {
ibiblio(name:"central", m2compatible:true)
ibiblio(name:"myrepo", root:"http://myrepo.com/nexus", m2compatible:true)
}
}
}
return file
}
// Main program
// ============
def ant = new AntBuilder()
def ivy = NamespaceBuilder.newInstance(ant, 'antlib:org.apache.ivy.ant')
generateSettingsFile("ivysettings.xml").deleteOnExit()
generateIvyFile("ivy.xml").deleteOnExit()
ivy.resolve()
ivy.publish(resolver:"myrepo", pubrevision:"1.0", publishivy:false) {
artifacts(pattern:"build/poms/[artifact].[ext]")
artifacts(pattern:"build/jars/[artifact].[ext]")
}
Notes:
More complex? Perhaps... however, if you're not generating the ivy file (using it to manage your dependencies) you can easily call the makepom task to generate the Maven POM files prior to upload into Nexus.
The REST APIs for Nexus work fine. I find them a little cryptic and of course a solution that uses them cannot support more than one repository manager (Nexus is not the only repository manager technology available).
The "deleteOnExit" File method call ensures the working files are cleaned up properly.

can't find IfxBulkCopy in IBM.Data.Informix 2.81.0.0

Q:
My question consists of two parts:
1- I want to use the following class IfxBulkCopy to insert large amount of data but this class doesn't exist in the dll IBM.Data.Informix 2.81.0.0 how to fix this problem.?
Note : the class exist in the IBM.Data.Informix 9.0.0.2 !but i can't use this version because we use an old version of the informix.
When i use the new version i get the following exception :
Invalid argument
StackTrace = " at IBM.Data.Informix.IfxConnection.ReplaceConnectionStringParms(String szValue, IfxConnSettings& connSettings)\r\n at IBM.Data.Informix.IfxConnection.set_ConnectionString(String value)\r\n at Common.DBConnectionForInformix..ctor(String ConnectionStr...
My .cs:
public static void InsertAsBulk(DataTable dt)
{
using (IfxConnection cn = new IfxConnection(ConfigurationManager.ConnectionStrings["aa"].ToString()))
{
cn.Open();
using (IfxBulkCopy copy = new IfxBulkCopy(cn))
{
copy.ColumnMappings.Add(1, 2);
copy.ColumnMappings.Add(2, 3);
copy.ColumnMappings.Add(3, 4);
copy.ColumnMappings.Add(4, 5);
copy.ColumnMappings.Add(5, 6);
copy.ColumnMappings.Add(6, 7);
copy.DestinationTableName = "schday";
copy.WriteToServer(dt);
}
}
}
2- Is the IfxBulkCopy use the transaction concept during the insertion operation or may result inconsistent data also .
Your connection string is fine. Do you have multiple versions of driver installed? I had same problem when I installed OAT, Informix driver and Informix Client SDK on same machine.
This solved my problem:
1. Uninstallation of driver and client sdk + windows restart
2. Installation of Client SDK together with data server driver
3. Checking system PATH variable. I added
C:\Program Files\IBM Informix Client SDK\bin
C:\Program Files\IBM Informix Client SDK\bin\netf20
to system PATH. I'm not sure what was the problem, maybe just changing PATH variable (without unistallation) can fix it.

Flyway output to SQL File

Is it possible to output the db migration to an SQL file instead of directly invoking database changes in flyway?
Most times this will not be needed as with Flyway the DB migrations themselves will already be written in SQL.
Yes it's possible and as far as I am concerned the feature is an absolute must for DBAs who don't want to allow flyway in prod.
I made do with modifying code from here, it's a dry run command for flyway, you can add a filewriter and write out migrationDetails:
https://github.com/killbill/killbill/commit/996a3d5fd096525689dced825eac7a95a8a7817e
I did it like so... Project structure (just copied it out of killbill's project and renamed package to flywaydr:
.
./main
./main/java
./main/java/com
./main/java/com/flywaydr
./main/java/com/flywaydr/CapturingMetaDataTable.java
./main/java/com/flywaydr/CapturingSqlMigrationExecutor.java
./main/java/com/flywaydr/DbMigrateWithDryRun.java
./main/java/com/flywaydr/MigrationInfoCallback.java
./main/java/com/flywaydr/Migrator.java
./main/java/org
./main/java/org/flywaydb
./main/java/org/flywaydb/core
./main/java/org/flywaydb/core/FlywayWithDryRun.java
In Migrator.java add (implement callback and put it in DbMigrateWithDryRun.java) :
} else if ("dryRunMigrate".equals(operation)) {
MigrationInfoCallback mcb = new MigrationInfoCallback();
flyway.dryRunMigrate();
MigrationInfoImpl[] migrationDetails = mcb.getPendingMigrationDetails();
if(migrationDetails.length>0){
writeMasterScriptToFile(migrationDetails);
}
}
Then to write stuff to file something like:
private static void writeMasterScriptToFile(MigrationInfoImpl[] migrationDetails){
FileWriter fw = null;
try{
String masterScriptLoc="path/to/file";
fw = new FileWriter(masterScriptLoc);
LOG.info("Writing output to " + masterScriptLoc);
for (final MigrationInfoImpl migration : migrationDetails){
Path file =Paths.get(migration.getResolvedMigration().getPhysicalLocation());
//if you want to copy actual script files parsed by flyway
Files.copy(file, Paths.get(new StringBuilder(scriptspathloc).append(File.separator).append(file.getFileName().toString()).toString()), REPLACE_EXISTING);
}
//or just get the sql
for (final SqlStatement sqlStatement : sqlStatements) {
//sqlStatement.getSql();
}
fw.write(stuff.toString());
} catch(Exception e){
LOG.error("Could not write to file, io exception was thrown.",e);
} finally{
try{fw.close();}catch(Exception e){LOG.error("Could not close file writer.",e);}
}
}
One last thing to mention, I compile and package this into a jar "with dependencies" (aka fatjar) via maven (google assembly plugin + jar with dependencies) and run it via command like below or you can include it as a dependency and call it via mvn exec:exec goal, which is something I had success with as well.
$ java -jar /path/to/flywaydr-fatjar.jar dryRunMigrate -regular.flyway.configs -etc -etc
I didnt find a way. Switched to mybatis migration. Looks quite nice.

Resources