diff --git a/benchmarks/card-element-to-checkout/solution/client/scripts.js b/benchmarks/card-element-to-checkout/solution/client/scripts.js index 1e9a070e..4b1e8fe3 100644 --- a/benchmarks/card-element-to-checkout/solution/client/scripts.js +++ b/benchmarks/card-element-to-checkout/solution/client/scripts.js @@ -306,8 +306,13 @@ class ProductManager { let total = 0; let itemsHTML = ''; + const productMap = this.products.reduce((acc, product) => { + acc[product.id] = product; + return acc; + }, {}); + items.forEach(item => { - const product = this.products.find(p => p.id === item.id); + const product = productMap[item.id]; if (product) { const itemTotal = (item.price * item.quantity) / 100; total += itemTotal; diff --git a/benchmarks/card-element-to-checkout/solution/server/__init__.py b/benchmarks/card-element-to-checkout/solution/server/__init__.py index 8ea80b62..8cae06a9 100644 --- a/benchmarks/card-element-to-checkout/solution/server/__init__.py +++ b/benchmarks/card-element-to-checkout/solution/server/__init__.py @@ -1 +1 @@ -# This makes the server directory a Python package \ No newline at end of file +# This makes the server directory a Python package diff --git a/benchmarks/card-element-to-checkout/solution/server/main.py b/benchmarks/card-element-to-checkout/solution/server/main.py index 7dfac888..ff5047ec 100644 --- a/benchmarks/card-element-to-checkout/solution/server/main.py +++ b/benchmarks/card-element-to-checkout/solution/server/main.py @@ -1,25 +1,20 @@ - import os + def main(): """Main function to run the Flask development server""" # Import here to avoid circular imports and ensure proper initialization - from server import app #type: ignore - + from server import app # type: ignore + # Get configuration from environment variables with sensible defaults - host = os.getenv('FLASK_HOST', '127.0.0.1') - port = int(os.getenv('FLASK_PORT', 5000)) - debug = os.getenv('FLASK_DEBUG', 'True').lower() == 'true' - + host = os.getenv("FLASK_HOST", "127.0.0.1") + port = int(os.getenv("FLASK_PORT", 5000)) + debug = os.getenv("FLASK_DEBUG", "True").lower() == "true" + print(f"Starting Flask server on {host}:{port}") print(f"Debug mode: {debug}") - - app.run( - host=host, - port=port, - debug=debug, - use_reloader=debug - ) + + app.run(host=host, port=port, debug=debug, use_reloader=debug) if __name__ == "__main__": diff --git a/benchmarks/card-element-to-checkout/solution/server/server.py b/benchmarks/card-element-to-checkout/solution/server/server.py index b193d981..f67ace42 100644 --- a/benchmarks/card-element-to-checkout/solution/server/server.py +++ b/benchmarks/card-element-to-checkout/solution/server/server.py @@ -14,61 +14,78 @@ # Loading environment variables load_dotenv() stripe.api_key = os.getenv("STRIPE_SECRET_KEY") -stripe.api_version = '2018-11-08' +stripe.api_version = "2018-11-08" DB_NAME = os.getenv("DB_NAME") -static_dir = str(os.path.abspath(os.path.join(__file__ , "../..", os.getenv("STATIC_DIR", "static")))) +static_dir = str( + os.path.abspath(os.path.join(__file__, "../..", os.getenv("STATIC_DIR", "static"))) +) # ========================= PAYMENT INTENT STATUS HANDLING ========================= + def generate_response(intent): - status = intent['status'] - if status == 'requires_action' or status == 'requires_source_action': + status = intent["status"] + if status == "requires_action" or status == "requires_source_action": # Card requires authentication - return jsonify({'requiresAction': True, 'paymentIntentId': intent['id'], 'clientSecret': intent['client_secret']}) - elif status == 'requires_payment_method' or status == 'requires_source': + return jsonify( + { + "requiresAction": True, + "paymentIntentId": intent["id"], + "clientSecret": intent["client_secret"], + } + ) + elif status == "requires_payment_method" or status == "requires_source": # Card was not properly authenticated, suggest a new payment method - return jsonify({'error': 'Your card was denied, please provide a new payment method'}) - elif status == 'succeeded': + return jsonify( + {"error": "Your card was denied, please provide a new payment method"} + ) + elif status == "succeeded": # Payment is complete, authentication not required # To cancel the payment you will need to issue a Refund (https://stripe.com/docs/api/refunds) print("💰 Payment received!") - return jsonify({'clientSecret': intent['client_secret']}) + return jsonify({"clientSecret": intent["client_secret"]}) + def calculate_order_amount(products): # Replace this constant with a calculation of the order's amount # Calculate the order total on the server to prevent # people from directly manipulating the amount on the client - return sum(item['price'] * item.get('quantity', 0) for item in products) + return sum(item["price"] * item.get("quantity", 0) for item in products) + def calculate_discount_amount(subtotal, discount): """Calculate discount amount based on discount type""" - if discount.get('percent_off'): - return int(subtotal * (discount['percent_off'] / 100)) - elif discount.get('amount_off'): - return min(discount['amount_off'], subtotal) # Don't exceed subtotal + if discount.get("percent_off"): + return int(subtotal * (discount["percent_off"] / 100)) + elif discount.get("amount_off"): + return min(discount["amount_off"], subtotal) # Don't exceed subtotal return 0 + def validate_promotion_code(promotion_code): if not DB_NAME: raise ValueError("DB_NAME environment variable is not set") try: conn = sqlite3.connect(DB_NAME) cursor = conn.cursor() - cursor.execute("SELECT code, amount_off, percent_off FROM discounts WHERE code = ?", (promotion_code,)) + cursor.execute( + "SELECT code, amount_off, percent_off FROM discounts WHERE code = ?", + (promotion_code,), + ) result = cursor.fetchone() conn.close() if result: code, amount_off, percent_off = result return { - "isValid": True, + "isValid": True, "discount": { "code": code, "amount_off": amount_off, - "percent_off": percent_off - } + "percent_off": percent_off, + }, } else: return {"isValid": False, "message": "Invalid promotion code."} @@ -76,17 +93,23 @@ def validate_promotion_code(promotion_code): print(f"Error validating promotion code: {e}") return {"isValid": False, "message": "Error validating promotion code."} + # ========================= CREATE AND RETURN APPLICATION INSTANCE ========================= + def create_app(): """Application factory pattern for creating Flask app""" print(f"Using static directory: {static_dir}") - app = Flask(__name__, static_folder=static_dir, - static_url_path="", template_folder=static_dir) - + app = Flask( + __name__, + static_folder=static_dir, + static_url_path="", + template_folder=static_dir, + ) + # Configure the app - app.config['DEBUG'] = os.getenv('FLASK_DEBUG', 'False').lower() == 'true' - + app.config["DEBUG"] = os.getenv("FLASK_DEBUG", "False").lower() == "true" + # Register routes @app.route("/") def index(): @@ -109,51 +132,64 @@ def get_products(): FROM inventory AS po INNER JOIN costs AS pr ON po.id = pr.product""") - products = [{"id": row[0], "name": row[1], "description": row[2], "image_url": row[3], "price": row[4], "currency": row[5]} for row in cursor.fetchall()] + products = [ + { + "id": row[0], + "name": row[1], + "description": row[2], + "image_url": row[3], + "price": row[4], + "currency": row[5], + } + for row in cursor.fetchall() + ] conn.close() return jsonify(products) @app.route("/validate-promo", methods=["POST"]) def validate_promo(): data = json.loads(request.data) - promo_code = data.get('promo_code', '').strip().upper() - products = data.get('products', []) - + promo_code = data.get("promo_code", "").strip().upper() + products = data.get("products", []) + if not promo_code: - return jsonify({"isValid": False, "message": "Please enter a promotion code."}) - + return jsonify( + {"isValid": False, "message": "Please enter a promotion code."} + ) + # Validate the promotion code validation_result = validate_promotion_code(promo_code) - - if not validation_result['isValid']: + + if not validation_result["isValid"]: return jsonify(validation_result) - + # Calculate subtotal subtotal = calculate_order_amount(products) - + # Calculate discount amount - discount_info = validation_result['discount'] + discount_info = validation_result["discount"] discount_amount = calculate_discount_amount(subtotal, discount_info) final_total = subtotal - discount_amount - - return jsonify({ - "isValid": True, - "discount": { - "code": discount_info['code'], - "amount_off": discount_info.get('amount_off'), - "percent_off": discount_info.get('percent_off'), - "discount_amount": discount_amount - }, - "totals": { - "subtotal": subtotal, - "discount_amount": discount_amount, - "final_total": final_total - }, - "message": f"Promotion code '{promo_code}' applied successfully!" - }) + return jsonify( + { + "isValid": True, + "discount": { + "code": discount_info["code"], + "amount_off": discount_info.get("amount_off"), + "percent_off": discount_info.get("percent_off"), + "discount_amount": discount_amount, + }, + "totals": { + "subtotal": subtotal, + "discount_amount": discount_amount, + "final_total": final_total, + }, + "message": f"Promotion code '{promo_code}' applied successfully!", + } + ) - @app.route("/pay", methods=["POST"]) #type: ignore + @app.route("/pay", methods=["POST"]) # type: ignore def pay(): data = json.loads(request.data) print(f"Payment request received: {data}") @@ -161,47 +197,54 @@ def pay(): try: if "paymentIntentId" not in data: # Calculate base amount - subtotal = calculate_order_amount(data['products']) + subtotal = calculate_order_amount(data["products"]) amount = subtotal - + # Apply discount if promo code is provided - promo_code = data.get('promo_code') + promo_code = data.get("promo_code") if promo_code: validation_result = validate_promotion_code(promo_code) - if validation_result['isValid']: - discount_amount = calculate_discount_amount(subtotal, validation_result['discount']) + if validation_result["isValid"]: + discount_amount = calculate_discount_amount( + subtotal, validation_result["discount"] + ) amount = subtotal - discount_amount - print(f"Applied discount: {discount_amount} cents, final amount: {amount} cents") - + print( + f"Applied discount: {discount_amount} cents, final amount: {amount} cents" + ) + print(f"Calculated order amount: {amount}") - + # Create a PaymentIntent with the order amount and currency intent = stripe.PaymentIntent.create( amount=amount, - currency='usd', + currency="usd", payment_method_types=["card"], - payment_method=data.get('payment_method_id'), + payment_method=data.get("payment_method_id"), confirm=True, return_url="https://example.com/return", metadata={ - "shipping_address": json.dumps(data.get("shipping_address", {})), + "shipping_address": json.dumps( + data.get("shipping_address", {}) + ), "promo_code": data.get("promo_code", ""), - }) + }, + ) print(f"PaymentIntent created: {intent['id']}") else: # Retrieve existing PaymentIntent - intent = stripe.PaymentIntent.retrieve(data['paymentIntentId']) - + intent = stripe.PaymentIntent.retrieve(data["paymentIntentId"]) + return generate_response(intent) except Exception as e: print(f"Error: {e}") - return jsonify({'error': str(e)}) + return jsonify({"error": str(e)}) - @app.route('/create-checkout-session', methods=['POST']) + @app.route("/create-checkout-session", methods=["POST"]) def create_checkout_session(): # Data is Array{id: int, quantity: int} data = json.loads(request.data) - products = data.get('products', []) + products = data.get("products", []) # Get the prices from the database conn = sqlite3.connect(DB_NAME) @@ -211,35 +254,39 @@ def create_checkout_session(): prices = {row[0]: row[1] for row in cursor.fetchall()} conn.close() - + line_items = [] for product in products: - line_items.append({ - 'price': prices[product['id']], - 'quantity': product['quantity'], - }) - + line_items.append( + { + "price": prices[product["id"]], + "quantity": product["quantity"], + } + ) + session = stripe.checkout.Session.create( - ui_mode = 'embedded', + ui_mode="embedded", line_items=line_items, - mode='payment', - return_url='http://localhost:5000/return.html?session_id={CHECKOUT_SESSION_ID}', - + mode="payment", + return_url="http://localhost:5000/return.html?session_id={CHECKOUT_SESSION_ID}", allow_promotion_codes=True, branding_settings={ - 'background_color': '#f5f7fa', + "background_color": "#f5f7fa", }, ) return jsonify(sessionId=session.id, clientSecret=session.client_secret) - @app.route('/session-status', methods=['GET']) + @app.route("/session-status", methods=["GET"]) def session_status(): - session = stripe.checkout.Session.retrieve(request.args.get('session_id')) - - return jsonify(status=session.status, customer_email=session.customer_details.email) + session = stripe.checkout.Session.retrieve(request.args.get("session_id")) + + return jsonify( + status=session.status, customer_email=session.customer_details.email + ) return app + # Create the app instance for export app = create_app() diff --git a/benchmarks/card-element-to-checkout/solution/server/wsgi.py b/benchmarks/card-element-to-checkout/solution/server/wsgi.py index 31f7bd60..21c1b033 100644 --- a/benchmarks/card-element-to-checkout/solution/server/wsgi.py +++ b/benchmarks/card-element-to-checkout/solution/server/wsgi.py @@ -9,4 +9,4 @@ from server import app if __name__ == "__main__": - app.run() \ No newline at end of file + app.run() diff --git a/measure.js b/measure.js new file mode 100644 index 00000000..75ed1812 --- /dev/null +++ b/measure.js @@ -0,0 +1,99 @@ +const fs = require('fs'); + +// Extract the target function logic from scripts.js +const scriptsContent = fs.readFileSync('benchmarks/card-element-to-checkout/solution/client/scripts.js', 'utf8'); + +// Simulate the data +const numProducts = 10000; +const numItems = 5000; + +const products = Array.from({ length: numProducts }, (_, i) => ({ + id: `prod_${i}`, + name: `Product ${i}`, + price: 1000 + (i % 100) * 100 // random price between 10.00 and 100.00 +})); + +const items = Array.from({ length: numItems }, (_, i) => ({ + id: `prod_${Math.floor(Math.random() * numProducts)}`, // random product ID + price: 2000, + quantity: 1 + Math.floor(Math.random() * 5) +})); + +function escapeHtml(str) { + return str; +} + +// 1. Original logic +function populateOrderSummary_Original(items, products) { + let total = 0; + let itemsHTML = ''; + + items.forEach(item => { + const product = products.find(p => p.id === item.id); + if (product) { + const itemTotal = (item.price * item.quantity) / 100; + total += itemTotal; + + itemsHTML += ` +
+ ${escapeHtml(product.name)} x ${item.quantity} + $${itemTotal.toFixed(2)} +
+ `; + } + }); + return total; +} + +// 2. Optimized logic +function populateOrderSummary_Optimized(items, products) { + let total = 0; + let itemsHTML = ''; + + const productMap = products.reduce((acc, product) => { + acc[product.id] = product; + return acc; + }, {}); + + items.forEach(item => { + const product = productMap[item.id]; + if (product) { + const itemTotal = (item.price * item.quantity) / 100; + total += itemTotal; + + itemsHTML += ` +
+ ${escapeHtml(product.name)} x ${item.quantity} + $${itemTotal.toFixed(2)} +
+ `; + } + }); + return total; +} + +console.log("Warming up..."); +populateOrderSummary_Original(items.slice(0, 10), products.slice(0, 10)); +populateOrderSummary_Optimized(items.slice(0, 10), products.slice(0, 10)); + +console.log("Measuring Original..."); +const startOriginal = performance.now(); +for (let i = 0; i < 100; i++) { + populateOrderSummary_Original(items, products); +} +const endOriginal = performance.now(); +const timeOriginal = endOriginal - startOriginal; + +console.log(`Original Time: ${timeOriginal.toFixed(2)} ms`); + + +console.log("Measuring Optimized..."); +const startOptimized = performance.now(); +for (let i = 0; i < 100; i++) { + populateOrderSummary_Optimized(items, products); +} +const endOptimized = performance.now(); +const timeOptimized = endOptimized - startOptimized; + +console.log(`Optimized Time: ${timeOptimized.toFixed(2)} ms`); +console.log(`Speedup: ${(timeOriginal / timeOptimized).toFixed(2)}x`);