Home » 2021 (Seite 3)

Archiv für das Jahr: 2021

JavaScript – Functions Scope / This

Closures – Function Scope

Mit einer Funktion lässt sich so etwas wie eine Klassendefinition erstellen. Wird von der Funktion eine (eingebettete) Funktion zurückgegeben, dann hat diese den ganzen scope ihrer umgebenden Funktion erhalten:

function remember(number){
   return function(){
      return number;
   }
}
f1 = remember(99);
f1();
//99

Vorsicht bei Übergabe von Funktionen!!

Im Gegensatz zu Java können Funktionen manchmal ‚Instanz-Variablen‘ haben, manchmal aber auch nicht. Auf was die This-Referenz der Funktion zeigt kann verwirrend unterschiedlich sein.
Im obigen Beispiel ist f1 eine „Objekt-Funktion“, d.h. eine Funktion mit einem Funktionspezifischen Scope (Java-Entwickler würden von einer Instanz sprechen).

Keinen non-global Closure hat hingegen eine Funktion, die zwar innerhal eines Objektes definiert ist, die aber dann (ohne umgebendes Objekt) als Referenz über geben wird:

> const dog = {
... age: 5,
... growOneYear: function(){
..... this.age += 1;
..... }
};
undefined
> dog.growOneYear();
undefined
> dog.age;
6
> function invokeTwice(cb){
... cb();
... cb();
}
undefined
> invokeTwice(dog.growOneYear);
undefined
> dog.age;
6 //<-- Hinaufzählen hat nicht funktioniert!

Wie man sieht hat die Funktionsreferenz dog.growOneYear das age Feld nicht in seinem Scope mit genommen!

Anders sieht es wiederum aus, wenn man eine Funktion mitgiebt, die durch eine andere Funktion erstellt wurde und deshalb deren Scope mit sich mit schleppt:

/* Hauptfunktion wird aufgerufen und gibt Unterfunktion zurück, die aber den Clusure hat der den Block der Hauptfunktion umfasst! */
> let catGrows = function(){
... age = 0;
... return () => {return age++;}
}(); 
undefined
> catGrows()
0
> catGrows()
1
> catGrows()
2
> invokeTwice(catGrows) /* Keine Ausgabe, aber intern wird gezählt */
undefined
> catGrows()
5
>

Das Beispiel mit dem „Function-in-Funktion-Scope“ funktioniert. Nur ist es äuserst unpraktisch, das man nur genau über eine Funktion zugriff auf das Objekt hat.

Nur wenn die Funktion auf dem Objekt aufgerufen wird, zeigt ihr This auf das Objekt:
>dog.growOneYear()

Damit invokeTwice das richtige Resultat liefert können wir auch programmieren:

> dog.age;
6
> invokeTwice(function(){dog.growOneYear();});
undefined
> dog.age;
8

gowOneYear operiert so immer auf dem mitgegebenen dog Objekt.



Die vielversprechendere Lösung ist es, via bind() Methode, der Funktion explizit das Objekt mitzugeben, auf das die This-Referenz der Funktion zeigen soll:



> objectBoundGrowOneYearFunction = dog.growOneYear.bind(dog);
[Function: bound growOneYear]
> invokeTwice(objectBoundGrowOneYearFunction);
undefined
> dog.age;
10
>

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.
Die 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 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=#

Define ORM in SQLAlchemy

References

Define a Parent-Child Relationship

class Driver(db.Model):
  __tablename__ = 'drivers'
  id = db.Column(db.Integer, privary_key=True)
  ...
  vehicles = db.relationship('Vehicle', backref='driver' , lazy=True)

class Vehicle(db.Model):
  __tablename__ = 'vehicles'
  id = db.Column(db.Integer, privary_key=True)
  ...
  driver_id = db.Column(db.Integer, db.ForeignKey('drivers.id'), nullable=False)

Beachte: Die backref heisst driver, das der relevante Foreign Key jedoch driver_id!

Erklärungen

Option:Erklärung:
lazy=True (default)lazy loading
lazy=’select‘eager loading
db.ForeignKey(‚drivers.id)1. ACHTUNG: Tabellennamen benutzen, nicht den Entity-Namen (drivers.id‚, nicht ‚Driver.id‘)!
2. Datentypen von FK und dessen Ziel müssen übereinstimmen.
Weitere relationship Konfig-Optionen:
collection_class = …
cascade = …

See: SQLALchemy ORM Relationship Docs
Beispiele:
collection_class = list
cascade = ’save-update‘ # OR: all, delete-orphan