Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# New Video - https://youtu.be/hQGE_CAo1PE
# New Video - https://youtu.be/Sq2B-LIZzjw

[<img src="assets/276.png?raw=true">](https://youtu.be/hQGE_CAo1PE)
[<img src="assets/277.png?raw=true">](https://youtu.be/Sq2B-LIZzjw)

# Consulting

Expand Down
Binary file removed assets/276.png
Binary file not shown.
Binary file added assets/277.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/contents.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,4 @@
- [274 - Protobuf vs JSON: Performance Benchmark & Size](../lessons/274)
- [275 - Go (Golang) vs TypeScript: Performance Benchmark](../lessons/275)
- [276 - Python vs JavaScript Performance: Best Backend Language 2026 (FastAPI vs Bun)](../lessons/276)
- [277 - SQLite vs PostgreSQL Performance & Comparison (2026)](../lessons/277)
121 changes: 121 additions & 0 deletions lessons/277/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Python vs JavaScript Performance: Best Backend Language 2026 (FastAPI vs Bun)

You can find tutorial [here](https://youtu.be/hQGE_CAo1PE).

## Schema

```sql
CREATE TABLE customer (
id SERIAL PRIMARY KEY,
username VARCHAR(50),
first_name VARCHAR(50),
last_name VARCHAR(50),
address VARCHAR(255)
);

CREATE TABLE product (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
price DECIMAL(10,2),
stock_quantity INTEGER
);

CREATE TABLE cart (
id SERIAL PRIMARY KEY,
customer_id BIGINT REFERENCES customer(id),
total DECIMAL(10,2)
);

CREATE TABLE cart_item (
id SERIAL PRIMARY KEY,
cart_id BIGINT REFERENCES cart(id),
product_id BIGINT REFERENCES product(id),
quantity INTEGER
);

CREATE TABLE "order" (
id SERIAL PRIMARY KEY,
customer_id BIGINT REFERENCES customer(id),
total DECIMAL(10,2)
);

CREATE TABLE order_item (
id SERIAL PRIMARY KEY,
order_id BIGINT REFERENCES "order"(id),
product_id BIGINT REFERENCES product(id),
quantity INTEGER
);

-- Create index on all foreign key columns for faster query performance.
CREATE INDEX cart_customer_id_idx ON cart (customer_id);
CREATE INDEX cart_item_cart_id_idx ON cart_item (cart_id);
CREATE INDEX cart_item_product_id_idx ON cart_item (product_id);
CREATE INDEX order_customer_id_idx ON "order" (customer_id);
CREATE INDEX order_item_order_id_idx ON order_item (order_id);
CREATE INDEX order_item_product_id_idx ON order_item (product_id);

-- Insert customers
INSERT INTO customer(username, first_name, last_name, address)
VALUES
('vmartin', 'Victor', 'Martin', '994 Lowndes Hill Park Road'),
('chauk', 'Christopher', 'Hauk', '4505 Cunningham Court'),
('hyoung', 'Howard', 'Young', '2001 Fairfax Drive'),
('jballard', 'John', 'Ballard', '1034 Ethels Lane'),
('jevans', 'James', 'Evans', '4669 Keyser Ridge Road'),
('egonzalez', 'Edgar', 'Gonzalez', '841 Marietta Street'),
('rbrumbelow', 'Ronald', 'Brumbelow', '4168 Rhapsody Street'),
('rharris', 'Raphael', 'Harris', '26 Red Bud Lane'),
('tfanning', 'Terry', 'Fanning', '2864 Bungalow Road'),
('ckelley', 'Claude', 'Kelley', '4896 Jarvisville Road');

-- Insert products
INSERT INTO product(name, price, stock_quantity)
VALUES
('Shampoo', 7.90, 100),
('Hairspray', 12.30, 100),
('Nail clippers', 19.00, 100),
('Towels', 32.80, 100),
('Conditioner', 8.80, 100),
('Detangler', 12.90, 100),
('Body wash ', 10.10, 100),
('Toilet paper ', 6.70, 100),
('Plunger', 23.90, 100),
('Mousse', 13.50, 100);
```

## Test

```sql
-- Create shopping cart
INSERT INTO cart(customer_id, total) VALUES (4, 0);

-- Add body wash to the cart
INSERT INTO cart_item(cart_id, product_id, quantity) VALUES (1, 7, 1);

-- Update value of the cart
UPDATE cart SET total = 10.10 WHERE customer_id = 4;

-- Create an order
INSERT INTO "order"(customer_id, total) VALUES (4, 25.90);

-- Add body wash to the order
INSERT INTO order_item(order_id, product_id, quantity) VALUES (1, 7, 1);

-- Reduce the stock quantity of the body wash
UPDATE product SET stock_quantity = 99 WHERE id = 7;

-- Delete shopping cart and items
DELETE FROM cart_item WHERE cart_id = 1;
DELETE FROM cart WHERE id = 1;

-- Select the order
SELECT
oi.id AS order_item_id,
p.name AS product_name,
oi.quantity,
p.price,
(oi.quantity * p.price) AS total_item_price
FROM order_item oi
JOIN product p ON oi.product_id = p.id
WHERE oi.order_id = 1;
```
107 changes: 107 additions & 0 deletions lessons/277/app/cmd/postgres/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package main

import (
"app/config"
"app/models"
"app/postgres"
"context"
"fmt"
"time"

mon "github.com/antonputra/go-utils/monitoring"
"github.com/antonputra/go-utils/util"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/prometheus/client_golang/prometheus"
)

func main() {
cfg := config.Load()

ctx, done := context.WithCancel(context.Background())
defer done()

// Create Prometheus metrics.
histLabels := []string{"op", "method"}

reg := prometheus.NewRegistry()
m := mon.NewMetrics("postgres", []string{}, []string{}, histLabels, reg)
mon.StartPrometheus(cfg.MetricsPort, reg)

db := postgres.Connect(ctx, cfg)

// Run the database migration to create tables, indexes, and populate them with sample data.
migrate(ctx, db, cfg)

// Run the main test.
test(ctx, cfg, db, m)
}

func test(ctx context.Context, cfg *config.Config, db *pgxpool.Pool, m *mon.Metrics) {
delay := cfg.Test.Delay

ticker := time.NewTicker(time.Duration(cfg.Test.Interval) * time.Second)
defer ticker.Stop()

for {
select {
case <-ticker.C:
if delay > 0 {
delay -= cfg.Test.Step
fmt.Printf("The current delay is %d microseconds.\n", delay)
}

default:
// Pick random customer from sample data
customer := cfg.Customers[util.Random(0, 9)]

// Pick random product from sample data
product := cfg.Products[util.Random(0, 9)]

// Create an empty shopping cart for the selected customer
cart := models.Cart{CustomerId: customer.Id, Total: 0.0}
err := cart.InsertCartPGX(ctx, db, m)
util.Fail(err, "fail to insert cart")

// Add product to the shopping cart
cartItem := models.CartItem{CartId: cart.Id, ProductId: product.Id, Quantity: int64(util.Random(1, 10))}
err = cartItem.InsertCartItemPGX(ctx, db, m)
util.Fail(err, "fail to insert cart item")

// Update value of the shopping cart
cart.Total = product.Price * float64(cartItem.Quantity)
err = cart.UpdateCartPGX(ctx, db, m)
util.Fail(err, "fail to update cart")

// Create an order
order := models.Order{CustomerId: cart.CustomerId, Total: cart.Total}
err = order.InsertOrderPGX(ctx, db, m)
util.Fail(err, "fail to create order")

// Add product to the order
orderItem := models.OrderItem{OrderId: order.Id, ProductId: cartItem.ProductId, Quantity: cartItem.Quantity}
err = orderItem.InsertOrderItemPGX(ctx, db, m)
util.Fail(err, "fail to insert order")

// Reduce the stock quantity of the product (set to random value)
product.StockQuantity = int64(util.Random(0, 100))
err = product.UpdateProductPGX(ctx, db, m)
util.Fail(err, "fail to update product")

// Delete shopping cart items
err = cartItem.DeleteCartItemPGX(ctx, db, m)
util.Fail(err, "fail to delete cart item")

// Delete shopping cart
err = cart.DeleteCartPGX(ctx, db, m)
util.Fail(err, "fail to delete cart")

// Create order report
orderReport := models.OrderReport{OrderId: order.Id}
orderReport.SelectOrderPGX(ctx, db, m)

if delay > 0 {
time.Sleep(time.Duration(delay) * time.Microsecond)
}
}
}
}
91 changes: 91 additions & 0 deletions lessons/277/app/cmd/postgres/migrate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package main

import (
"app/config"
"context"

"github.com/antonputra/go-utils/util"
"github.com/jackc/pgx/v5/pgxpool"
)

func migrate(ctx context.Context, db *pgxpool.Pool, cfg *config.Config) {
// PostgreSQL driver automatically prepares and caches statements.
tables := []string{
`
CREATE TABLE IF NOT EXISTS customer (
id SERIAL PRIMARY KEY,
username VARCHAR(50),
first_name VARCHAR(50),
last_name VARCHAR(50),
address VARCHAR(255)
);
`,
`
CREATE TABLE IF NOT EXISTS product (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
price DECIMAL(10,2),
stock_quantity INTEGER
);
`,
`
CREATE TABLE IF NOT EXISTS cart (
id SERIAL PRIMARY KEY,
customer_id BIGINT REFERENCES customer(id),
total DECIMAL(10,2)
);
`,
`
CREATE TABLE IF NOT EXISTS cart_item (
id SERIAL PRIMARY KEY,
cart_id BIGINT REFERENCES cart(id),
product_id BIGINT REFERENCES product(id),
quantity INTEGER
);
`,
`
CREATE TABLE IF NOT EXISTS "order" (
id SERIAL PRIMARY KEY,
customer_id BIGINT REFERENCES customer(id),
total DECIMAL(10,2)
);
`,
`
CREATE TABLE IF NOT EXISTS order_item (
id SERIAL PRIMARY KEY,
order_id BIGINT REFERENCES "order"(id),
product_id BIGINT REFERENCES product(id),
quantity INTEGER
);
`,
}

indexes := []string{
`CREATE INDEX IF NOT EXISTS cart_customer_id_idx ON cart (customer_id);`,
`CREATE INDEX IF NOT EXISTS cart_item_cart_id_idx ON cart_item (cart_id);`,
`CREATE INDEX IF NOT EXISTS cart_item_product_id_idx ON cart_item (product_id);`,
`CREATE INDEX IF NOT EXISTS order_customer_id_idx ON "order" (customer_id);`,
`CREATE INDEX IF NOT EXISTS order_item_order_id_idx ON order_item (order_id);`,
`CREATE INDEX IF NOT EXISTS order_item_product_id_idx ON order_item (product_id);`,
}

for _, sql := range tables {
_, err := db.Exec(ctx, sql)
util.Fail(err, "failed to create tables")
}

for _, sql := range indexes {
_, err := db.Exec(ctx, sql)
util.Fail(err, "failed to create indexes")
}

for _, c := range cfg.Customers {
err := c.InsertCustomerPGX(ctx, db)
util.Fail(err, "failed to create customer")
}

for _, p := range cfg.Products {
err := p.InsertProductPGX(ctx, db)
util.Fail(err, "failed to create product")
}
}
Loading