Tuesday, March 11, 2025

#11 @Output

 

Understanding @Output() in Angular 19

The @Output() decorator in Angular 19 is used to send data from a child component to a parent component. It allows child components to emit events, which the parent component can listen to and respond to.


Step-by-Step Guide with Example

We will create a simple Angular 19 project where a child component emits an event, and the parent component listens for it.


Step 1: Create a New Angular 19 Project

Ensure you have Angular CLI installed:

npm install -g @angular/cli@latest

Now, create a new Angular project:

ng new angular-output-demo
cd angular-output-demo
ng serve

Step 2: Generate a Child Component

Create a new child component that will emit an event to the parent:

ng generate component components/child

This creates:

  • child.component.ts
  • child.component.html
  • child.component.scss

Step 3: Implement @Output() in the Child Component

Modify child.component.ts:

import { Component, EventEmitter, Output } from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.scss']
})
export class ChildComponent {
  // Define an EventEmitter to send data to the parent
  @Output() messageEvent = new EventEmitter<string>();

  sendMessage() {
    this.messageEvent.emit('Hello from Child Component!');
  }
}

Step 4: Update the Child Component Template

Modify child.component.html:

<div class="child-container">
  <h3>Child Component</h3>
  <button (click)="sendMessage()">Send Message to Parent</button>
</div>

Step 5: Listen for Events in the Parent Component

Modify app.component.ts to receive the event:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  receivedMessage: string = '';

  // Method to handle event from child
  onMessageReceived(message: string) {
    this.receivedMessage = message;
  }
}

Step 6: Update the Parent Component Template

Modify app.component.html:

<h2>Parent Component</h2>
<p><strong>Message from Child:</strong> {{ receivedMessage }}</p>

<!-- Pass event listener to the child -->
<app-child (messageEvent)="onMessageReceived($event)"></app-child>

Step 7: Add Some Styling (Optional)

Modify child.component.scss:

.child-container {
  border: 2px solid #007bff;
  padding: 15px;
  margin: 10px;
  border-radius: 8px;
  text-align: center;
  background-color: #f0f8ff;
}

button {
  background-color: #007bff;
  color: white;
  border: none;
  padding: 10px 15px;
  cursor: pointer;
  border-radius: 5px;
}

button:hover {
  background-color: #0056b3;
}

Step 8: Run the Project

Start the Angular application:

ng serve

Open the browser at http://localhost:4200, click the "Send Message to Parent" button, and see the message update in the parent component.


Key Takeaways

โœ… @Output() allows child components to send data to parent components.
โœ… EventEmitter<T> is used to emit events with a specific data type.
โœ… The parent listens for the emitted event using event binding:

<app-child (messageEvent)="onMessageReceived($event)"></app-child>

Would you like to modify this example to pass more complex data like objects or arrays? ๐Ÿš€

#10 @Input()

 

Understanding @Input() in Angular 19

The @Input() decorator in Angular 19 allows a child component to receive data from a parent component. It is commonly used to pass dynamic values, making components reusable and modular.


Step-by-Step Guide with Example

We will create a simple Angular 19 project where a parent component passes data to a child component using @Input().


Step 1: Create a New Angular 19 Project

Make sure you have the latest Angular CLI installed:

npm install -g @angular/cli@latest

Now, create a new Angular project:

ng new angular-input-demo
cd angular-input-demo
ng serve

Step 2: Generate a Child Component

Create a new child component that will receive data using @Input():

ng generate component components/user-card

This creates:

  • user-card.component.ts
  • user-card.component.html
  • user-card.component.scss
  • user-card.component.spec.ts

Step 3: Define @Input() in the Child Component

Modify user-card.component.ts to accept input from the parent:

import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-user-card',
  templateUrl: './user-card.component.html',
  styleUrls: ['./user-card.component.scss']
})
export class UserCardComponent {
  // Define inputs to receive data from the parent component
  @Input() name: string = 'Guest';
  @Input() age: number = 0;
  @Input() city: string = 'Unknown';
}

Step 4: Update the Child Component Template

Modify user-card.component.html:

<div class="user-card">
  <h3>User Information</h3>
  <p><strong>Name:</strong> {{ name }}</p>
  <p><strong>Age:</strong> {{ age }}</p>
  <p><strong>City:</strong> {{ city }}</p>
</div>

Step 5: Use <app-user-card> in the Parent Component

Modify app.component.html:

<h2>Passing Data to Child Component</h2>

<app-user-card name="Alice" age="28" city="New York"></app-user-card>
<app-user-card name="Bob" age="35" city="Los Angeles"></app-user-card>
<app-user-card name="Charlie" age="22" city="Chicago"></app-user-card>

Step 6: Add Some Styling (Optional)

Modify user-card.component.scss:

.user-card {
  border: 1px solid #ccc;
  padding: 15px;
  margin: 10px;
  border-radius: 8px;
  text-align: left;
  background-color: #f9f9f9;
}

Step 7: Run the Project

Start the Angular application:

ng serve

Open your browser at http://localhost:4200, and you should see the user information passed from the parent component to the child component.


Key Takeaways

โœ… @Input() allows parent components to pass data to child components.
โœ… Child components use @Input() to declare properties that accept values.
โœ… Parent components bind values to @Input() properties like:

<app-user-card name="Alice"></app-user-card>

Would you like to extend this example with real dynamic data from an API or a list of users? ๐Ÿš€

#9 Signals

 

Understanding Angular 19 Signals

In Angular 19, signals are a reactivity model introduced to improve performance, simplify state management, and provide fine-grained change detection without relying on RxJS. Signals help track state changes efficiently and work seamlessly with Angularโ€™s rendering system.

Key Features of Signals

  1. Declarative State Management - Makes state tracking more predictable.
  2. Automatic Dependency Tracking - Updates components when signal values change.
  3. Optimized Rendering - Reduces unnecessary component re-renders.
  4. Better Performance - No need for manual ChangeDetectionStrategy.OnPush.

Step-by-Step Angular 19 Signals Example

We will create a basic Angular 19 application where we use signals to manage a counter.


Step 1: Create a New Angular 19 Project

Ensure you have Angular CLI 19 installed. If not, update it:

npm install -g @angular/cli@latest

Now, create a new Angular project:

ng new angular-signals-demo
cd angular-signals-demo

Select SCSS or any other styling option based on your preference.


Step 2: Install Required Dependencies

Angular Signals are built-in, so you donโ€™t need additional packages.

Just ensure your project is running:

ng serve

Step 3: Create a Counter Service using Signals

Generate a service to manage our counter state using signals.

ng generate service services/counter

Now, modify counter.service.ts:

import { Injectable, signal } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class CounterService {
  // Define a signal with an initial value of 0
  count = signal(0);

  // Method to increment the count
  increment() {
    this.count.set(this.count() + 1);
  }

  // Method to decrement the count
  decrement() {
    this.count.set(this.count() - 1);
  }

  // Method to reset the count
  reset() {
    this.count.set(0);
  }
}

Step 4: Use Signals in a Component

Generate a new component to display and update the counter.

ng generate component components/counter

Now, update counter.component.ts:

import { Component } from '@angular/core';
import { CounterService } from 'src/app/services/counter.service';

@Component({
  selector: 'app-counter',
  templateUrl: './counter.component.html',
  styleUrls: ['./counter.component.scss'],
})
export class CounterComponent {
  constructor(public counterService: CounterService) {}

  // Methods to modify the count
  increment() {
    this.counterService.increment();
  }

  decrement() {
    this.counterService.decrement();
  }

  reset() {
    this.counterService.reset();
  }
}

Step 5: Update the Counter Component HTML

Modify counter.component.html:

<div class="counter-container">
  <h2>Counter with Angular 19 Signals</h2>
  <p>Current Count: {{ counterService.count() }}</p>

  <button (click)="increment()">+</button>
  <button (click)="decrement()">-</button>
  <button (click)="reset()">Reset</button>
</div>

Step 6: Add Counter Component to App Component

Modify app.component.html to include the counter:

<h1>Welcome to Angular 19 Signals Demo</h1>
<app-counter></app-counter>

Step 7: Style the Counter (Optional)

Modify counter.component.scss:

.counter-container {
  text-align: center;
  margin-top: 20px;

  h2 {
    font-size: 1.5rem;
    margin-bottom: 10px;
  }

  p {
    font-size: 1.2rem;
    font-weight: bold;
  }

  button {
    font-size: 1rem;
    margin: 5px;
    padding: 10px 15px;
    cursor: pointer;
    border: none;
    background-color: #007bff;
    color: white;
    border-radius: 5px;
  }

  button:hover {
    background-color: #0056b3;
  }

  button:nth-child(2) {
    background-color: #dc3545;
  }

  button:nth-child(2):hover {
    background-color: #c82333;
  }

  button:nth-child(3) {
    background-color: #6c757d;
  }

  button:nth-child(3):hover {
    background-color: #5a6268;
  }
}

Step 8: Run the Project

Start the Angular application:

ng serve

Open the browser at http://localhost:4200 and see your signal-powered counter in action!


Key Takeaways

  • signal(value) creates a reactive state variable.
  • .set(newValue) updates the signalโ€™s value.
  • .update(fn) modifies the value based on the current state.
  • Signals are synchronous and automatically notify the UI of changes.

This example demonstrates how easy it is to use signals in Angular 19 for state management. Would you like to extend this with more features like async operations or effects? ๐Ÿš€


#8.4 CRUD- SQL Lite (WIP.....)

Angular [<19] CRUD application to store data in SQLite instead of localStorage, follow these steps:


๐Ÿ›  Steps to Implement SQLite in Angular

  1. Set up an SQLite database using an API (Node.js + Express + SQLite3).
  2. Modify the Angular service to perform CRUD operations using HTTP requests.
  3. Update the component to call the service instead of using localStorage.

๐Ÿ“Œ Step 1: Set Up SQLite API (Node.js + Express + SQLite3)

We'll create an Express API that interacts with SQLite.

1๏ธโƒฃ Install Dependencies

Run this in your backend folder:

npm init -y
npm install express sqlite3 cors body-parser

2๏ธโƒฃ Create server.js (Express API)

const express = require('express');
const sqlite3 = require('sqlite3').verbose();
const cors = require('cors');
const bodyParser = require('body-parser');

const app = express();
const port = 3000;

app.use(cors());
app.use(bodyParser.json());

// Connect to SQLite
const db = new sqlite3.Database('./employees.db', sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, (err) => {
    if (err) console.error(err.message);
    console.log('Connected to SQLite database.');
});

// Create Employee Table
db.run(`CREATE TABLE IF NOT EXISTS employees (
    empid INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT,
    contactNo TEXT,
    emailId TEXT,
    city TEXT,
    state TEXT,
    pinCode TEXT,
    address TEXT
)`);

// Get all employees
app.get('/employees', (req, res) => {
    db.all('SELECT * FROM employees', [], (err, rows) => {
        if (err) return res.status(500).json({ error: err.message });
        res.json(rows);
    });
});

// Add a new employee
app.post('/employees', (req, res) => {
    const { name, contactNo, emailId, city, state, pinCode, address } = req.body;
    db.run(`INSERT INTO employees (name, contactNo, emailId, city, state, pinCode, address) VALUES (?, ?, ?, ?, ?, ?, ?)`,
        [name, contactNo, emailId, city, state, pinCode, address],
        function (err) {
            if (err) return res.status(500).json({ error: err.message });
            res.json({ empid: this.lastID });
        }
    );
});

// Update an employee
app.put('/employees/:id', (req, res) => {
    const { name, contactNo, emailId, city, state, pinCode, address } = req.body;
    const { id } = req.params;
    db.run(`UPDATE employees SET name=?, contactNo=?, emailId=?, city=?, state=?, pinCode=?, address=? WHERE empid=?`,
        [name, contactNo, emailId, city, state, pinCode, address, id],
        function (err) {
            if (err) return res.status(500).json({ error: err.message });
            res.json({ updated: this.changes });
        }
    );
});

// Delete an employee
app.delete('/employees/:id', (req, res) => {
    const { id } = req.params;
    db.run('DELETE FROM employees WHERE empid = ?', [id], function (err) {
        if (err) return res.status(500).json({ error: err.message });
        res.json({ deleted: this.changes });
    });
});

// Start server
app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}`);
});

Run the API:

node server.js

๐Ÿ“Œ Step 2: Modify Angular Service (employee.service.ts)

We will replace localStorage with HTTP API calls.

Create employee.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

export interface Employee {
  empid?: number;
  name: string;
  contactNo: string;
  emailId: string;
  city: string;
  state: string;
  pinCode: string;
  address: string;
}

@Injectable({
  providedIn: 'root'
})
export class EmployeeService {
  private apiUrl = 'http://localhost:3000/employees';

  constructor(private http: HttpClient) {}

  getEmployees(): Observable<Employee[]> {
    return this.http.get<Employee[]>(this.apiUrl);
  }

  addEmployee(employee: Employee): Observable<any> {
    return this.http.post(this.apiUrl, employee);
  }

  updateEmployee(employee: Employee): Observable<any> {
    return this.http.put(`${this.apiUrl}/${employee.empid}`, employee);
  }

  deleteEmployee(empid: number): Observable<any> {
    return this.http.delete(`${this.apiUrl}/${empid}`);
  }
}

๐Ÿ“Œ Step 3: Modify app.component.ts

Replace Local Data with API Calls

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { EmployeeService, Employee } from './employee.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  
  employeeForm: FormGroup;
  employeeList: Employee[] = [];
  selectedEmployee: Employee | null = null;

  constructor(private employeeService: EmployeeService) {
    this.createForm();
  }

  ngOnInit() {
    this.loadEmployees();
  }

  createForm() {
    this.employeeForm = new FormGroup({
      empid: new FormControl(null),
      name: new FormControl('', [Validators.required]),
      contactNo: new FormControl(''),
      emailId: new FormControl(''),
      city: new FormControl(''),
      state: new FormControl(''),
      pinCode: new FormControl('', [Validators.required, Validators.minLength(6)]),
      address: new FormControl('')
    });
  }

  loadEmployees() {
    this.employeeService.getEmployees().subscribe(data => {
      this.employeeList = data;
    });
  }

  onSave() {
    if (this.selectedEmployee) {
      this.employeeService.updateEmployee(this.employeeForm.value).subscribe(() => {
        this.loadEmployees();
        this.reset();
      });
    } else {
      this.employeeService.addEmployee(this.employeeForm.value).subscribe(() => {
        this.loadEmployees();
        this.reset();
      });
    }
  }

  onEdit(employee: Employee) {
    this.selectedEmployee = employee;
    this.employeeForm.patchValue(employee);
  }

  onDelete(empid: number) {
    if (confirm("Are you sure you want to delete?")) {
      this.employeeService.deleteEmployee(empid).subscribe(() => {
        this.loadEmployees();
      });
    }
  }

  reset() {
    this.employeeForm.reset();
    this.selectedEmployee = null;
  }
}

๐Ÿ“Œ Step 4: Update app.module.ts

Ensure you import HttpClientModule.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, ReactiveFormsModule, HttpClientModule],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

๐ŸŽฏ Final Steps

  1. Start the SQLite API
    node server.js
    
  2. Run Angular App
    ng serve
    
  3. Test CRUD operations in the UI ๐ŸŽ‰

๐Ÿš€ What We Changed

โœ… Replaced localStorage with an SQLite database
โœ… Created a Node.js API with SQLite for CRUD operations
โœ… Updated Angular to use HTTP services


This setup provides a real database instead of localStorage, making the app persistent and scalable. Let me know if you need more modifications! ๐Ÿš€๐Ÿ”ฅ


====================================================================


Since you're using Angular 19, the core structure remains the same, but there are some minor updates in best practices, TypeScript versions, and RxJS changes. I'll provide the updated Angular 19 implementation with SQLite using a Node.js backend.


๐Ÿ›  Steps to Implement SQLite with Angular 19

  1. Set up an SQLite database with an API (Node.js + Express + SQLite3).
  2. Modify Angular Service using HttpClient to perform CRUD operations.
  3. Update the Component and Forms using the latest Angular 19 best practices.
  4. Ensure compatibility with RxJS changes (tap(), subscribe() syntax, etc.).

๐Ÿ“Œ Step 1: Set Up SQLite API (Node.js + Express + SQLite3)

1๏ธโƒฃ Install Dependencies

Run the following command inside the backend folder:

npm init -y
npm install express sqlite3 cors body-parser dotenv

2๏ธโƒฃ Create server.js (Express API)

require('dotenv').config();
const express = require('express');
const sqlite3 = require('sqlite3').verbose();
const cors = require('cors');
const bodyParser = require('body-parser');

const app = express();
const port = process.env.PORT || 3000;

app.use(cors());
app.use(bodyParser.json());

// Connect to SQLite
const db = new sqlite3.Database('./employees.db', sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, (err) => {
    if (err) console.error(err.message);
    console.log('Connected to SQLite database.');
});

// Create Employee Table
db.run(`CREATE TABLE IF NOT EXISTS employees (
    empid INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    contactNo TEXT NOT NULL,
    emailId TEXT NOT NULL,
    city TEXT,
    state TEXT,
    pinCode TEXT,
    address TEXT
)`);

// Get all employees
app.get('/employees', (req, res) => {
    db.all('SELECT * FROM employees', [], (err, rows) => {
        if (err) return res.status(500).json({ error: err.message });
        res.json(rows);
    });
});

// Add a new employee
app.post('/employees', (req, res) => {
    const { name, contactNo, emailId, city, state, pinCode, address } = req.body;
    db.run(`INSERT INTO employees (name, contactNo, emailId, city, state, pinCode, address) VALUES (?, ?, ?, ?, ?, ?, ?)`,
        [name, contactNo, emailId, city, state, pinCode, address],
        function (err) {
            if (err) return res.status(500).json({ error: err.message });
            res.json({ empid: this.lastID });
        }
    );
});

// Update an employee
app.put('/employees/:id', (req, res) => {
    const { name, contactNo, emailId, city, state, pinCode, address } = req.body;
    const { id } = req.params;
    db.run(`UPDATE employees SET name=?, contactNo=?, emailId=?, city=?, state=?, pinCode=?, address=? WHERE empid=?`,
        [name, contactNo, emailId, city, state, pinCode, address, id],
        function (err) {
            if (err) return res.status(500).json({ error: err.message });
            res.json({ updated: this.changes });
        }
    );
});

// Delete an employee
app.delete('/employees/:id', (req, res) => {
    const { id } = req.params;
    db.run('DELETE FROM employees WHERE empid = ?', [id], function (err) {
        if (err) return res.status(500).json({ error: err.message });
        res.json({ deleted: this.changes });
    });
});

// Start server
app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}`);
});

Run the API

node server.js

๐Ÿ“Œ Step 2: Modify Angular Service (employee.service.ts)

We will replace localStorage with HTTP API calls.

Create employee.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

export interface Employee {
  empid?: number;
  name: string;
  contactNo: string;
  emailId: string;
  city: string;
  state: string;
  pinCode: string;
  address: string;
}

@Injectable({
  providedIn: 'root'
})
export class EmployeeService {
  private apiUrl = 'http://localhost:3000/employees';

  constructor(private http: HttpClient) {}

  getEmployees(): Observable<Employee[]> {
    return this.http.get<Employee[]>(this.apiUrl);
  }

  addEmployee(employee: Employee): Observable<any> {
    return this.http.post(this.apiUrl, employee);
  }

  updateEmployee(employee: Employee): Observable<any> {
    return this.http.put(`${this.apiUrl}/${employee.empid}`, employee);
  }

  deleteEmployee(empid: number): Observable<any> {
    return this.http.delete(`${this.apiUrl}/${empid}`);
  }
}

๐Ÿ“Œ Step 3: Modify app.component.ts

Replace Local Data with API Calls

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { EmployeeService, Employee } from './employee.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  
  employeeForm!: FormGroup;
  employeeList: Employee[] = [];
  selectedEmployee: Employee | null = null;

  constructor(private employeeService: EmployeeService) {}

  ngOnInit() {
    this.createForm();
    this.loadEmployees();
  }

  createForm() {
    this.employeeForm = new FormGroup({
      empid: new FormControl(null),
      name: new FormControl('', [Validators.required]),
      contactNo: new FormControl('', Validators.required),
      emailId: new FormControl('', Validators.required),
      city: new FormControl(''),
      state: new FormControl(''),
      pinCode: new FormControl('', [Validators.required, Validators.minLength(6)]),
      address: new FormControl('')
    });
  }

  loadEmployees() {
    this.employeeService.getEmployees().subscribe(data => {
      this.employeeList = data;
    });
  }

  onSave() {
    if (this.selectedEmployee) {
      this.employeeService.updateEmployee(this.employeeForm.value).subscribe(() => {
        this.loadEmployees();
        this.reset();
      });
    } else {
      this.employeeService.addEmployee(this.employeeForm.value).subscribe(() => {
        this.loadEmployees();
        this.reset();
      });
    }
  }

  onEdit(employee: Employee) {
    this.selectedEmployee = employee;
    this.employeeForm.patchValue(employee);
  }

  onDelete(empid: number) {
    if (confirm("Are you sure you want to delete?")) {
      this.employeeService.deleteEmployee(empid).subscribe(() => {
        this.loadEmployees();
      });
    }
  }

  reset() {
    this.employeeForm.reset();
    this.selectedEmployee = null;
  }
}

๐Ÿ“Œ Step 4: Update app.module.ts

Ensure you import HttpClientModule.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, ReactiveFormsModule, HttpClientModule],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

๐ŸŽฏ Final Steps

  1. Start the SQLite API
    node server.js
    
  2. Run Angular App
    ng serve
    
  3. Test CRUD operations in the UI ๐ŸŽ‰

๐Ÿš€ What We Updated for Angular 19

โœ… Removed any in TypeScript
โœ… Ensured strict types for RxJS (tap(), subscribe())
โœ… Used ! operator to avoid null issues
โœ… Modernized form validation


Now your Angular 19 app works with SQLite via Node.js! ๐ŸŽฏ๐Ÿš€ Let me know if you need any changes. ๐Ÿ”ฅ

# 8.3 SQLite Hands-on with Python

 

SQLite Shenanigans: The Funniest Database Adventure Ever

Welcome to the World of SQLite!

Ah, SQLite. The database that doesn't need a server, yet still has the audacity to demand our attention! Today, we embark on a hilarious yet educational journey into the land of SQL wizardry, where databases exist in .db files and SQL statements are our spells.

So, buckle up and get ready to dive into the wonderful (and sometimes frustrating) world of SQLite with Python!


Ex 1: Opening a Database โ€“ The "Hello World" of SQLite

Before we can do anything, we need to open a database. Itโ€™s like saying "hi" before you ask for a favor.

import sqlite3

try:
    with sqlite3.connect("my.db") as conn:
        print(f"Opened SQLite database with version {sqlite3.sqlite_version} successfully.")
except sqlite3.OperationalError as e:
    print("Failed to open database:", e)

If all goes well, SQLite gives us a nod of approval. If not, well, expect an error message that makes you question your life choices.


Ex 2: Creating Tables โ€“ Because We Need a Place to Put Stuff

We canโ€™t just throw our data into the void. We need tables! Hereโ€™s how we create them:

import sqlite3

sql_statements = [
    """CREATE TABLE IF NOT EXISTS projects (
            id INTEGER PRIMARY KEY,
            name text NOT NULL,
            begin_date DATE,
            end_date DATE
        );""",

    """CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY,
            name TEXT NOT NULL,
            priority INT,
            project_id INT NOT NULL,
            status_id INT NOT NULL,
            begin_date DATE NOT NULL,
            end_date DATE NOT NULL,
            FOREIGN KEY (project_id) REFERENCES projects (id)
        );"""
]

try:
    with sqlite3.connect('my.db') as conn:
        cursor = conn.cursor()
        for statement in sql_statements:
            cursor.execute(statement)
        conn.commit()
        print("Tables created successfully.")
except sqlite3.OperationalError as e:
    print("Failed to create tables:", e)

And just like that, we have tables! SQLite doesnโ€™t complainโ€”yet.


Ex 3: Inserting Records โ€“ Filling Our Database with Meaningful Chaos

Creating tables is nice, but theyโ€™re just empty shells without data. Let's add some records!

import sqlite3

def add_project(conn, project):
    sql = ''' INSERT INTO projects(name,begin_date,end_date)
              VALUES(?,?,?) '''
    cur = conn.cursor()
    cur.execute(sql, project)
    conn.commit()
    return cur.lastrowid

def add_task(conn, task):
    sql = '''INSERT INTO tasks(name,priority,status_id,project_id,begin_date,end_date)
             VALUES(?,?,?,?,?,?) '''
    cur = conn.cursor()
    cur.execute(sql, task)
    conn.commit()
    return cur.lastrowid

def main():
    try:
        with sqlite3.connect('my.db') as conn:
            project = ('Cool App with SQLite & Python', '2015-01-01', '2015-01-30')
            project_id = add_project(conn, project)
            print(f'Created a project with the id {project_id}')
            tasks = [
                ('Analyze the requirements of the app', 1, 1, project_id, '2015-01-01', '2015-01-02'),
                ('Confirm with user about the top requirements', 1, 1, project_id, '2015-01-03', '2015-01-05')
            ]
            for task in tasks:
                task_id = add_task(conn, task)
                print(f'Created task with the id {task_id}')
    except sqlite3.Error as e:
        print(e)

if __name__ == '__main__':
    main()

Now our database has some actual data! Itโ€™s alive! ๐Ÿคฏ


Ex 4: Updating Data โ€“ Because Plans Always Change

First, let's change a single column, because why not?

import sqlite3

sql = 'UPDATE tasks SET priority = ? WHERE id = ?'

try:
    with sqlite3.connect('my.db') as conn:
        cursor = conn.cursor()
        cursor.execute(sql, (2,1))
        conn.commit()
except sqlite3.OperationalError as e:
    print(e)

Now, let's go crazy and update multiple columns!

import sqlite3

sql = 'UPDATE tasks SET end_date = ?'

try:
    with sqlite3.connect('my.db') as conn:
        cursor = conn.cursor()
        cursor.execute(sql, ('2015-02-03',))
        conn.commit()
except sqlite3.Error as e:
    print(e)

Change is good, right?


Ex 5 & 6: Querying the Database โ€“ Letโ€™s See What We Did

To check if we actually did things right, let's retrieve some data:

import sqlite3

try:
    with sqlite3.connect('my.db') as conn:
        cur = conn.cursor()
        cur.execute('select id, name, priority from tasks')
        rows = cur.fetchall()
        for row in rows:
            print(row)
except sqlite3.OperationalError as e:
    print(e)

Want a specific record? Say no more!

import sqlite3

try:
    with sqlite3.connect('my.db') as conn:
        cur = conn.cursor()
        cur.execute('SELECT id, name, priority FROM tasks WHERE id =?', (1,))
        row = cur.fetchone()
        if row:
            print(row)
except sqlite3.OperationalError as e:
    print(e)

Ex 7: Reusable Code โ€“ The Lazy Programmerโ€™s Dream

We love functions. They do things so we donโ€™t have to.

import sqlite3

def get_task_by_id(id: int) -> tuple:
    try:
        with sqlite3.connect('my.db') as conn:
            cur = conn.cursor()
            cur.execute('select id, name, priority from tasks where id =?', (id,))
            row = cur.fetchone()
            return row, None
    except sqlite3.OperationalError as e:
        return None, e      

if __name__ == '__main__':
    task, error = get_task_by_id(1)
    if error is not None:
        print(f'Error: {error}')
    else:
        print(task)

And thatโ€™s a wrap! ๐ŸŽ‰ You now have the power to create, update, and retrieve data like a true SQLite ninja. Use it wisely (or recklessly, your call). Happy coding! ๐Ÿ˜†

Monday, March 10, 2025

#8.2 SqLite CRUD - Advanced Topics

 Hereโ€™s an SQLite tutorial expansion covering Joins, Indexing, and Transactions in four short modules (~30 minutes total). This will help students optimize queries, combine data from multiple tables, and ensure data integrity.


๐ŸŽฏ Goal of the Tutorial

  • Understand Joins to combine multiple tables.
  • Learn Indexing for faster queries.
  • Use Transactions to maintain database integrity.

๐Ÿ“Œ Module 1: Understanding Joins (8 mins)

๐Ÿ”น Why Use Joins?

Joins help combine data from multiple tables using common keys.

๐Ÿ”น Creating Example Tables

Students Table

CREATE TABLE students (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    course_id INTEGER
);

Courses Table

CREATE TABLE courses (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    course_name TEXT NOT NULL
);

Inserting Data

INSERT INTO courses (course_name) VALUES ('Computer Science'), ('Mathematics');
INSERT INTO students (name, course_id) VALUES ('Alice', 1), ('Bob', 2);

๐Ÿ”น Performing Joins

INNER JOIN (Most Common)

SELECT students.name, courses.course_name
FROM students
JOIN courses ON students.course_id = courses.id;

โœ”๏ธ Shows only students with a matching course.

LEFT JOIN (All Students, Even Without a Course)

SELECT students.name, courses.course_name
FROM students
LEFT JOIN courses ON students.course_id = courses.id;

โœ”๏ธ Includes students without a course (NULL values).

RIGHT JOIN (Not Supported in SQLite)

SQLite doesnโ€™t support RIGHT JOIN, but we can swap table positions and use LEFT JOIN.

๐Ÿ›  Exercise 1

  1. Create a teachers table.
  2. Use a JOIN to show which teacher is assigned to which course.

๐Ÿ“Œ Module 2: Indexing for Performance (7 mins)

๐Ÿ”น What is Indexing?

  • Speeds up queries by reducing search time.
  • Works like a book index.

๐Ÿ”น Creating an Index

CREATE INDEX idx_students_course ON students(course_id);

โœ”๏ธ Speeds up searches involving course_id.

๐Ÿ”น Checking Execution Time

EXPLAIN QUERY PLAN 
SELECT * FROM students WHERE course_id = 1;

โœ”๏ธ Shows whether the query is using an index.

๐Ÿ”น Deleting an Index

DROP INDEX idx_students_course;

๐Ÿ›  Exercise 2

  1. Create an index for the students' names.
  2. Run a SELECT query with and without the index.

๐Ÿ“Œ Module 3: Transactions for Data Integrity (8 mins)

๐Ÿ”น What is a Transaction?

  • Ensures multiple operations succeed or fail together.
  • Uses BEGIN, COMMIT, and ROLLBACK.

๐Ÿ”น Example: Safe Bank Transfer

BEGIN TRANSACTION;

UPDATE students SET course_id = 2 WHERE name = 'Alice';

-- Simulate an error before committing
ROLLBACK; 

SELECT * FROM students;  -- Alice's course remains unchanged

โœ”๏ธ ROLLBACK prevents incomplete operations from saving.

๐Ÿ”น COMMIT: Finalizing Transactions

BEGIN TRANSACTION;

UPDATE students SET course_id = 2 WHERE name = 'Alice';
COMMIT;

SELECT * FROM students;  -- Alice's course is now updated

โœ”๏ธ COMMIT permanently saves the changes.

๐Ÿ›  Exercise 3

  1. Begin a transaction to update multiple students.
  2. Rollback before committing and check if data changes.

๐Ÿ“Œ Module 4: Combining Joins, Indexing, and Transactions (7 mins)

๐Ÿ”น Complex Query Example

BEGIN TRANSACTION;

SELECT students.name, courses.course_name
FROM students
JOIN courses ON students.course_id = courses.id
WHERE students.name LIKE 'A%';

COMMIT;

โœ”๏ธ Finds students whose names start with 'A' and ensures query execution in a transaction.

๐Ÿ”น Optimizing Queries

CREATE INDEX idx_courses_name ON courses(course_name);

โœ”๏ธ Speeds up searching for courses by name.

๐Ÿ›  Final Exercise

  1. Create a new table for enrollments and use a JOIN to show which student is in which course.
  2. Use transactions to ensure enrollment updates succeed.
  3. Optimize the query using an index.

๐ŸŽฏ Summary of the Tutorial

โœ”๏ธ Module 1: Joins (Combining tables)
โœ”๏ธ Module 2: Indexing (Faster queries)
โœ”๏ธ Module 3: Transactions (Data integrity)
โœ”๏ธ Module 4: Combining them in real-world queries


๐Ÿ“Œ Next Steps ( We Will Study later !)

  • Try using foreign keys to enforce relationships.
  • Experiment with nested joins and multi-table indexes.
  • Learn about triggers for automated actions.

Would you like sample SQL scripts for practice? ๐Ÿš€

#8.1 SQLite tutorial basics

 Here's a 30-minute SQLite tutorial divided into four modules to explain CRUD principles for undergraduate students. Each module takes about 7-8 minutes and includes theory, examples, and exercises.


๐ŸŽฏ Goal of the Tutorial

  • Learn the basics of SQLite.
  • Understand CRUD (Create, Read, Update, Delete) operations.
  • Use SQLite commands to manage a database.

๐Ÿ“ Module 1: Introduction to SQLite & Setting Up (7 mins)

๐Ÿ”น What is SQLite?

  • A lightweight, self-contained database.
  • No need for a separate server (unlike MySQL/PostgreSQL).
  • Used in mobile apps, embedded systems, and local applications.

๐Ÿ”น Installing SQLite

Windows:

  1. Download SQLite from SQLite official site.
  2. Extract and open the sqlite3.exe file.
  3. Run:
    sqlite3
    

Linux/macOS:

  1. Install via terminal:
    sudo apt install sqlite3   # Ubuntu/Debian
    brew install sqlite        # macOS
    
  2. Run SQLite:
    sqlite3
    

๐Ÿ›  Exercise 1: Creating a Database

sqlite3 students.db

โœ”๏ธ This creates a students.db file where we will store our tables.


๐Ÿ“Œ Module 2: Creating and Reading Data (7 mins)

๐Ÿ”น Creating a Table (C in CRUD)

We create a students table:

CREATE TABLE students (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT UNIQUE,
    age INTEGER,
    course TEXT
);

๐Ÿ”น Inserting Data

INSERT INTO students (name, email, age, course)
VALUES ('Alice', 'alice@example.com', 20, 'Computer Science');

๐Ÿ”น Reading Data (R in CRUD)

SELECT * FROM students;

๐Ÿ›  Exercise 2: Insert and Read

  1. Insert two more student records.
  2. Run SELECT * FROM students; to check.

โœ๏ธ Module 3: Updating and Deleting Data (7 mins)

๐Ÿ”น Updating Data (U in CRUD)

Updating Aliceโ€™s course:

UPDATE students 
SET course = 'Data Science' 
WHERE name = 'Alice';

๐Ÿ”น Deleting Data (D in CRUD)

DELETE FROM students WHERE name = 'Alice';

๐Ÿ›  Exercise 3:

  1. Update another studentโ€™s age.
  2. Delete a student record.



๐Ÿš€ Module 4: Advanced Queries & Best Practices (7 mins)

๐Ÿ”น Filtering Data

SELECT * FROM students WHERE age > 18;

๐Ÿ”น Sorting Data

SELECT * FROM students ORDER BY name ASC;

๐Ÿ”น Counting Records

SELECT COUNT(*) FROM students;

๐Ÿ›  Final Exercise

  1. Retrieve students older than 21.
  2. Count the number of students.

Dropping Tables and Databases in SQLite

SQLite allows you to delete tables using DROP TABLE, but it does not support dropping databases directly since an SQLite database is just a file.


๐Ÿ”น Dropping a Table in SQLite

To delete a table along with all its data, use:

DROP TABLE table_name;

Example

DROP TABLE students;

โœ”๏ธ This removes the students table permanently.
โ— Warning: This action cannot be undone.


๐Ÿ”น Dropping a Database in SQLite

Since SQLite databases are just files, you delete a database by removing the database file from the system.

Steps to Drop an SQLite Database

  1. Find the database file (e.g., mydatabase.db).
  2. Delete it manually using the terminal or command prompt.

Using Command Line

Windows

del mydatabase.db

Linux/macOS

rm mydatabase.db

โœ”๏ธ This permanently deletes the database file.
โ— Warning: This cannot be undone unless you have a backup.


๐Ÿ”น Checking Before Dropping

Before dropping a table, check if it exists:

DROP TABLE IF EXISTS students;

โœ”๏ธ This prevents errors if the table doesnโ€™t exist.


๐Ÿ”น Alternative: Clearing a Table Instead of Dropping

If you just want to clear all data but keep the table structure, use:

DELETE FROM students;

โœ”๏ธ Removes all records but keeps the table.

OR

DELETE FROM students WHERE 1=1;

โœ”๏ธ Same as above but can be used dynamically in scripts.

Would you like a script to automate table deletions? ๐Ÿš€



=======================================================================

๐ŸŽฏ Summary of the Tutorial

โœ”๏ธ Module 1: Setup and creating a database
โœ”๏ธ Module 2: Creating and reading records
โœ”๏ธ Module 3: Updating and deleting data
โœ”๏ธ Module 4: Advanced queries


๐Ÿ“Œ Next Steps

  • Try integrating SQLite with Python, Node.js, or JavaScript.
  • Experiment with joins, indexing, and transactions.

Would you like me to prepare slides or code files for this tutorial? ๐Ÿš€

#11 @Output

  Understanding @Output() in Angular 19 The @Output() decorator in Angular 19 is used to send data from a child component to a parent co...