Home » 2021 » August

Archiv für den Monat: August 2021

React JS – Einführung

Diese wunderbare Einführung in das React JS Gui Framework macht es völlig unnötig hier noch mehr zu schreiben.

Dass ich trotzdem noch etwas Schreibe ist mehr als Mittel gedacht für mich selbst einig Merkpunkte nochmals zu recapitulieren.

Building Blocks

Importieren von

import React from 'react';
import ReactDOM from 'react-dom';

GUI-Compoent-Modell

Nun können React Componenten als Klassen angelegt werden:

class Square extends React.Component {
  render() {
    return (
      <button className="square" onClick={function() { console.log('click'); }}>
        {this.props.value}
      </button>
    );
  }
}

class Board extends React.Component {
    renderSquare(i) {
        return (<Square value={this.props.squares[i]} onClick={() => this.props.onClick(i)} />);
    }

    render() {
        return (
            <div>
                <div className="board-row">
                    {this.renderSquare(0)}
                    {this.renderSquare(1)}
                    {this.renderSquare(2)}
                </div>
                <div className="board-row">
                    {this.renderSquare(3)}
                    {this.renderSquare(4)}
                    {this.renderSquare(5)}
                </div>
                <div className="board-row">
                    {this.renderSquare(6)}
                    {this.renderSquare(7)}
                    {this.renderSquare(8)}
                </div>
            </div>
        );
    }
}

Obiger Code zeigt die definition von zwei Componenten (Board und Square). Was durch diese Component im GUI angezeigt wird ist dadurch definiert, was ihre render Methode zurück gibt.
Dieses Rückgabe-Object wird auch React Element genannt.
Im obigen Beispiel wird das React Element mittels JSX Notation beschrieben, welche HTML imitiert.
Das Mitgabe von Sub-Elementen (-Componenten) and den Parser geschieht im Beispiel mit:

return (<Square value={this.props.squares[i]} onClick={() => this.props.onClick(i)} />);

Die Component-Sub-Klasse (im Beispiel ‚Square‘) wird also wie ein HTML-Tag referenziert!

Parameter-Übergabe und Modell-GUI-Synchronisation

Parameter-Übergabe

Wird eine Sub-Component z.B. so ins GUI einbezogen …

return (<Square meinWert={myVar}>

dann kann sie nachher in der Sqare-Component so ausgelesen werden:

this.parms.meinWert

Status und Modell-GUI-Synchronisation

Status Definition

Der von React verwaltete State muss im Constructor definiert werden:

class Game extends React.Component {
    constructor(props){
        super(props);
        this.state = {
            meineVar: 'Mein Wert' 
        };
    }

Beachte:

  • super(props) ist zu programmieren!
  • Der State einer Component ist privat!
Status Update

Mittels this.setState() wird der State wird in der render Methode vom Programmierer nachgeführt. React führt automatisch die States der Unter-Komponenten nach.

this.setState({meineVar: 'Hallo Welt'});

In Flask: JavaScript als File auslagern

Symptom: Dieser seltsame Fehler:

sqlalchemy.exc.DataError: (psycopg2.errors.InvalidTextRepresentation) FEHLER: ungültige Eingabesyntax für Typ integer: »app.js«
LINE 3: WHERE todolists.id = ‚app.js‘

Lösung: Korrektes Referenzieren des Javascript-Files in einer Flask-Applikation:

In Flask apps stehen JavaScript und CSS files standardmässig in einem static genannten directory neben dem templates Directory, das die HTML templates enthält.

Im HTML-File wird ein File (z.B. Namens app.js) dann so referenziert:

<script src="{{url_for('static', filename='app.js')}}"></script>

Achtung: Das Scripts-Tag muss am Ende des Bodies stehen.

SQL CROSS APPLY function

Reference

SQL Cross Apply and Outer Apply: The Complete Guide

Oracle SQL – Know how

Concatenate the different row values of the same group into on row per group.

LISTAGG Function, see: Sql PIVOT and string concatenation aggregate

SQL Pivot

Referenzen

Oracle PIVOT – Introduction to Oracle PIVOT clause

SQL Pivot: Converting Rows to Columns

Sql PIVOT and string concatenation aggregate (Schwierig :-))

Kurz-Erklärung

SQL Pivot kann benutzt werden um Gruppierungen innerhalb eines Resultat-Sets zu machen und pro Gruppe zusätzliche Kolonnen zu extrahieren.

Hätten wir z.B. ein statement:

SELECT MONAT, REGENMENGE FROM REPORT;

MonatRegenmenge
1100
2212
3322

Wenn man daraus dieseses Format erstellen möchte:

JanuarFebruarMärzApril
100212322

… würde man dies mit folgendem Pivot-Statement erreichen:

SELECT MONAT, REGENMENGE FROM REPORT
PIVOT max(REGENMENGE) -- Aggregatsfunktion fuer mehrere werte fuer denselben Monat
FOR MONAT
IN ( '1' as JANUAR, '2' as FEBRUAR, '3' as MÄRZ, '4' as APRIL, ...)

WordPress Error: Aktualisierung fehlgeschlagen. Die Antwort ist keine gültige JSON-Antwort.

Workpress weigert sich, den Beitrag zu speicher. Fehlermeldung:
The error „Aktualisierung fehlgeschlagen. Die Antwort ist keine gültige JSON-Antwort.“

Gefundene Lösung:

Es hat sich in jenem Fall herausgestellt, dass WordPress mit dem Text 'import java.io. File' seine Mühe hatte (weshalb ich auch diesen Eintrag nicht speichern könnte würde ich eben diesen Import richtig schreiben 🙂

Java JDBC program to execute update statements from a file

package db.werkzeuge;

import java. io.File; //!!Wrong written because if not WordPress hesitates to save this.
import java.io.IOException;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.sql.*;


class DBLoad {

    public static void main (String[] args) {
        try {
            String startTime =  time();
            System.out.println("Started at: " + startTime);
            String url = "jdbc:oracle:thin:@myserver.ch:12121:STMP01";
            Connection conn = DriverManager.getConnection(url,"user1","password1");
            int i = 1;
            int iSuccess = 0;
            for(String stmt : readStatements("in/file_with_update_statements.sql")){
                try {
                    execute(conn, stmt);
                    iSuccess++;
                }catch(Exception e){
                    System.out.println("ERROR: Could not update row nbr " + i + ". Statement was: " + stmt);
                    System.out.println(e);
                }
                i++;
            }
            System.out.println("\nEND: Updated " + iSuccess + " records on DB.");
            System.out.println("Start time: " + startTime + " / " + " Finished at: " + time());
//            conn.commit();
            conn.close();
        } catch (Exception e) {
            System.err.println("Got an exception! ");
            System.err.println(e.getMessage());
        }

    }

    private static List<String> readStatements(String fileName){
        File file = new File(DBLoad.class.getClassLoader().getResource(fileName).getFile());
        try (Stream<String> stream = Files.lines(file.toPath())) {
            return stream.filter(s -> !s.startsWith("--")).map(s -> s.replaceAll(";", "")).collect(Collectors.toList());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new ArrayList<>();
    }

    private static void execute(Connection conn, String stmt) throws SQLException {
        System.out.print("X");
        Statement st = conn.createStatement();
        st.executeUpdate(stmt);
    }

    public static String time() {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("HH:mm:ss");
        LocalDateTime now = LocalDateTime.now();
        return dtf.format(now);
    }
}

Remark: ‚import java. io.File‚ habe ich absichtlich falsch geschrieben, da sonst WordPress sich weigern würde den Beitrag abzuspeichern. Fehlermeldung: „Aktualisierung fehlgeschlagen. Die Antwort ist keine gültige JSON-Antwort.“

Refernce used: Alvin Alexanders Blog über JDBC …

SQLAlchemy/Python DB-Manipulation basierend of ORM Model

Wenn z.B. ein Python File vorliegt, dass DB-Connectivity und Entitätenmodell definiert:
(Python interpreter wurde aus dem Verzeichnis mit dem app.py gestartet. FLASK_APP Environmentvariable zeigte auch auf das app.py File.)

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:admin@localhost:5432/todoDB'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

class TodoList(db.Model):
  __tablename__ = 'todolists'
  id = db.Column(db.Integer, primary_key=True)
  name = db.Column(db.String(), nullable=False)
  todos = db.relationship('Todo', backref='list', lazy=True)

  def __repr__(self):
    return f'<TodoList {self.id} {self.name}>'

class Todo(db.Model):
  __tablename__ = 'todos'
  id = db.Column(db.Integer, primary_key=True)
  description = db.Column(db.String(), nullable=False)
  completed = db.Column(db.Boolean, nullable=False, default=False)
  list_id = db.Column(db.Integer, db.ForeignKey('todolists.id'), nullable=False)

  def __repr__(self):
    return f'<Todo {self.id} {self.description}, list {self.list_id}>'

Beachte: Der Foreign Key heisst ‚list_id‚, die ‚backref‘ wird aber mit ‚list‚ angegeben und auch das TodoList-Parent-Objekt wird (siehe unten) an die Referenz Todo.list angehängt.

Dann können mittels Python auf der Commandline folgendermassen Entitäten erstellt und gespeichert werden:

C:\tmp\Python_Workspace1\step4-todoapp-crud-lists>python
Python 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 16:30:00) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from app import db, Todo, TodoList
>>> list1 = TodoList(name='Haushalt')
>>> todo1 = Todo(description='putzen')
>>> todo2 = Todo(description='kochen')
>>> todo1.list=list1
>>> todo2.list=list1
>>> list1.id=3
>>> db.session.add(list1)
>>> db.session.commit()

Resultat:

todoDB=# select * from todos;
 id | description | completed | list_id
----+-------------+-----------+---------
  6 | putzen      | f         |       3
  7 | kochen      | f         |       3
(5 Zeilen)


todoDB=# select * from todolists;
 id |     name
----+---------------
  3 | Haushalt
(3 Zeilen)


todoDB=#