CRUD ऑपरेशन्स

CRUD का मतलब है create, read, update और delete: stored data पर program के चार बुनियादी operations। Stored data के साथ काम करने वाले ज़्यादातर features इन्हीं से बनते हैं। Contact list में contact जोड़ना contacts table में एक row create करता है, उसे खोलना वह row read करता है, phone number बदलना उसे update करता है, और contact हटाना उसे delete करता है — या उसे deleted के रूप में mark करता है।

Web application में हर operation तीन layers में दिखता है: UI में user का action, API को भेजी गई HTTP request, और database में SQL statement। यह lesson इन तीनों को जोड़ता है, ताकि आप वहाँ action करें जहाँ user करता है और नतीजे की पुष्टि वहाँ करें जहाँ data store होता है।

यह क्यों ज़रूरी है

Data के कई defects असल में CRUD defects होते हैं: form जो field स्वीकार करता है वह कभी save नहीं होता, edit गलत record बदल देता है या ऐसा field मिटा देता है जिसे किसी ने छुआ नहीं, delete related rows पीछे छोड़ देता है या ज़रूरत से ज़्यादा मिटा देता है। Screen अक्सर इन्हें छिपा लेती है: हरा "Saved" message सिर्फ़ इतना साबित करता है कि request बिना error के ख़त्म हुई, यह नहीं कि सही data सही row तक पहुँचा।

CRUD एक आसान coverage checklist भी है। Feature जिस भी तरह के records संभालता है, हर एक के लिए पूछें: क्या चारों operations मौजूद हैं, हर operation कौन कर सकता है, और क्या हर एक टेस्ट हुआ? Create और read लगभग हर test में चल जाते हैं, क्योंकि बाकी tests को data चाहिए; update और delete तभी टेस्ट होते हैं जब कोई उनकी planning करे, और यही वे operations हैं जो data खो सकते हैं या उजागर कर सकते हैं।

चार operations और हर एक से क्या अपेक्षा है

हर operation का stored data पर एक अपेक्षित असर होता है, और वही असर आप टेस्ट करते हैं। पिछले lesson की primary key चारों को जोड़ती है: create record को उसकी key देता है; read, update और delete उसी से ठीक एक record तक पहुँचते हैं।

  • Create: नई primary key के साथ एक नया record, हर भेजा गया field सही column में, और वे values जो system ख़ुद set करता है, जैसे default status और created_at।
  • Read: stored data जैसा है वैसा लौटता है, key से एक record या filtered list, और read कुछ नहीं बदलता।
  • Update: intended record के intended fields बदलते हैं, बाकी सब वैसा ही रहता है, और table में updated_at हो तो वह आगे बढ़ता है।
  • Delete: record product से गायब हो जाता है। Database में वह या तो हटा दिया जाता है (hard delete), या रखकर mark किया जाता है, जैसे deleted_at timestamp से (soft delete)। जिस row को दूसरी rows refer करती हैं, उसका hard delete पिछले lesson के foreign key delete rule के मुताबिक चलता है: related rows भी delete होती हैं (CASCADE), उनका reference NULL करके उन्हें रखा जाता है (SET NULL), या delete reject होता है (RESTRICT या NO ACTION)। Soft delete असल में एक update है, इसलिए कोई delete rule नहीं चलता और related rows को application को ख़ुद handle करना पड़ता है।

एक operation, तीन layers: UI, HTTP और SQL

UI में click API को HTTP request भेजता है, और API एक या ज़्यादा SQL statements चलाता है। HTTP request में एक method होता है, यानी action, और एक path, यानी target: GET /contacts/7 contact 7 माँगता है, और response में 200 OK जैसा status code आता है। PUT पूरा नया record भेजता है, PATCH सिर्फ़ बदलने वाले fields। SQL की तरफ़ INSERT rows जोड़ता है, SELECT rows पढ़ता है, UPDATE मौजूदा rows की values बदलता है और DELETE rows हटाता है; WHERE clause statement को सिर्फ़ उन rows तक सीमित करता है जो उसकी condition से match होती हैं।

REST API में, यानी उस आम style में जहाँ हर path किसी record या records के collection का नाम होता है, आम mapping यह है: create के लिए POST और INSERT, read के लिए GET और SELECT, update के लिए PUT या PATCH और UPDATE, और delete के लिए दोनों layers में DELETE। ये चार statements उस हिस्से का मूल हैं जिसे आम तौर पर SQL की data manipulation language (DML) कहा जाता है। HTTP methods और REST API basics वाले lessons requests को गहराई से सिखाते हैं, और अगला lesson SELECT सिखाता है।

यह mapping एक convention है, नियम नहीं, और जहाँ यह अलग होती है वहीं tests को देखना चाहिए। एक POST /orders order के लिए एक INSERT और हर item के लिए एक INSERT चला सकता है। Delete button ऐसा UPDATE चला सकता है जो deleted_at set करे; RFC 9110 DELETE को URI और resource के बीच का संबंध हटाने के रूप में परिभाषित करता है, data मिटाने के वादे के रूप में नहीं। Cancel button POST /appointments/7/cancel भेज सकता है, जो CRUD की भाषा में update है। असल में क्या होता है, यह API contract, developer या database बताता है।

Contact list का उदाहरण: हर CRUD operation एक UI action, एक HTTP request और एक SQL statement है, और हर एक database में जाँचने लायक अलग निशान छोड़ता है। वैचारिक मॉडल
OperationHTTP requestREST conventionSQL statementDatabase में जाँच
CreateUI: contact जोड़ेंPOST /contactsINSERT INTO contacts …ठीक एक नई row: नई id, हर field, created_at set
ReadUI: contact 7 खोलेंGET /contacts/7SELECT … FROM contacts WHERE id = 7Screen row से match करे; कुछ नहीं बदला
UpdateUI: phone edit करेंPATCH /contacts/7UPDATE contacts SET phone = … WHERE id = 7सिर्फ़ row 7 का phone बदला; updated_at आगे बढ़ा
DeleteUI: contact delete करेंDELETE /contacts/7DELETE FROM contacts WHERE id = 7या UPDATE … SET deleted_at (soft delete)Row हटी या flag हुई; related rows design के मुताबिक
  • Outline वाला cell: API operation के नाम से अलग statement चला सकता है

एक आम REST web application: असली mapping API contract और code तय करते हैं, और एक request कई statements चला सकती है।

पाठ संस्करण
CRUD    UI action        HTTP request        SQL statement
------  ---------------  ------------------  --------------------------------------------
Create  Add contact      POST /contacts      INSERT INTO contacts (...) VALUES (...)
Read    Open contact 7   GET /contacts/7     SELECT * FROM contacts WHERE id = 7
Update  Edit phone       PATCH /contacts/7   UPDATE contacts SET phone = ... WHERE id = 7
Delete  Delete contact   DELETE /contacts/7  DELETE FROM contacts WHERE id = 7

आज़माएँ: SQL INSERT जनरेटर

पहले product में verify करें, फिर database में

हर operation वैसे करें जैसे user या client करता है, UI या API के ज़रिए। Database में सीधे rows लिखना उस validation और logic को छोड़ देता है जिसे आपको टेस्ट करना है; सीधे INSERT statements preconditions तैयार करने के लिए हैं। फिर नीचे दिए points पर नतीजा जाँचें। Negative tests में, जैसे invalid input या बिना permission वाला user, database में कोई बदलाव नहीं दिखना चाहिए, आधी-अधूरी row भी नहीं।

सुरक्षित तरीके से काम करें: जाँच के लिए SELECT इस्तेमाल करें, और INSERT, UPDATE या DELETE सिर्फ़ उस test environment में चलाएँ जिसे बदलने की आपको अनुमति है, production में स्पष्ट अनुमति के बिना कभी नहीं। WHERE clause के बिना UPDATE या DELETE table की हर row बदल देता है, इसलिए पहले WHERE लिखें और उसे SELECT में चलाकर देखें कि कौन-सी rows match होती हैं।

  • Response: screen पर message, या API से मिला status code और body।
  • Product के ज़रिए read-back: page reload करें या अलग GET भेजें। इससे सिर्फ़ आपका input दोहराने वाली screen और पुराना cached data पकड़ में आता है; update से पहले और बाद के response की तुलना हर बदला हुआ field दिखाती है।
  • Database: row को उसकी primary key से select करें और वह देखें जो product शायद न दिखाए: field mapping, default values, timestamps, soft-delete flags, rounding और Arabic text की encoding।
  • आस-पास की rows: create ने ठीक एक row जोड़ी; update ने दूसरी rows और न छुए गए columns नहीं बदले; delete ने related rows design के मुताबिक handle कीं, और record lists, search और totals से गायब है।

आज़माएँ: REST API टेस्टर आज़माएँ: JSON डिफ़ आज़माएँ: SQL क्वेरी वैलिडेटर

Worked example: appointment reschedule करना

Requirement: "Patient किसी आने वाले appointment को उसी doctor के किसी दूसरे खाली slot पर ले जा सकता है। पुराना slot फिर से खाली हो जाता है।" User के लिए यह एक update है; database में दो tables बदलनी चाहिए।

Tester पहले state नोट करता है: patient 1203 का appointment 7, slot 41 में 09:00 बजे है, और यह उस patient का अकेला booked appointment है। फिर वह UI में उसे 10:30 पर reschedule करता है, जो PATCH भेजता है, "My appointments" reload करता है, जहाँ 10:30 दिखना चाहिए, और इस section के अंत की queries चलाता है। हर query को "match होने वाली rows के ये columns दिखाओ" की तरह पढ़ें: IN (41, 58) दोनों में से किसी भी id से match करता है, और COUNT(*) match होने वाली rows की गिनती लौटाता है। हर query एक अलग defect पकड़ती है:

  • Query 1: अगर status या patient_id बदल गया, तो update ने ऐसे columns छुए जो उसे नहीं छूने थे; अगर slot_id अब भी 41 है, तो confirmation screen ने सिर्फ़ भेजा गया data दिखाया।
  • Query 2: अगर slot 41 अब भी booked है, तो कोई भी 09:00 फिर से book नहीं कर पाएगा; अगर slot 58 booked mark नहीं हुआ, तो कोई दूसरा patient भी 10:30 book कर सकता है। Patient को कुछ गलत नहीं दिखता; यह सिर्फ़ database में या किसी दूसरे patient के view में दिखता है।
  • Query 3: अगर API ने row 7 update करने की जगह नया appointment insert किया, तो count 2 है, यानी ऐसी double booking जो confirmation screen नहीं दिखाएगी।
-- Before: appointment 7 (patient 1203) is booked in slot 41 at 09:00
-- UI: "Reschedule" to 10:30 -> PATCH /api/appointments/7 {"slot_id": 58} -> 200 OK

-- 1. The appointment changed, and only the intended columns
SELECT id, patient_id, slot_id, status, updated_at
FROM appointments
WHERE id = 7;
-- expected: slot_id 58, patient_id 1203, status 'booked', updated_at later

-- 2. Both slots changed
SELECT id, starts_at, is_booked
FROM slots
WHERE id IN (41, 58);
-- expected: 41 is_booked false, 58 is_booked true

-- 3. No second appointment was created
SELECT COUNT(*)
FROM appointments
WHERE patient_id = 1203 AND status = 'booked';
-- expected: 1, the same as before

आज़माएँ: SQL फ़ॉर्मेटर

आम गलतियाँ

  • Success message पर भरोसा करना: "Saved" या 200 OK बताता है कि request पूरी हुई, यह नहीं कि सही data सही row तक पहुँचा।
  • Create और read टेस्ट करना और update व delete भूल जाना, या delete को सिर्फ़ बिना related data वाले records पर टेस्ट करना।
  • SQL से data बदलकर उसे feature का test कहना; direct writes सिर्फ़ preconditions के लिए हैं।
  • WHERE clause के बिना, या shared environment में, UPDATE या DELETE चलाना और दूसरों के काम का test data बर्बाद कर देना।
  • यह मान लेना कि mapping one-to-one है: design soft delete का हो और row के गायब होने की उम्मीद करना, या इसका उल्टा। Requirement का इरादा पक्का करें।

QA का नज़रिया

CRUD वाली सोच test analysis के दौरान शुरू होती है। इसके लिए एक आसान tool CRUD matrix है: records के प्रकार (contacts, orders, invoices) एक तरफ़, उन पर काम करने वाले roles या features दूसरी तरफ़, और हर cell में C, R, U या D। खाली या अनपेक्षित cells सवाल बन जाते हैं। Invoice कौन delete कर सकता है? Delete hard है या soft? Invoice lines का क्या होता है? Database schema और test database का read-only access जल्दी माँगें।

Execution के दौरान हर layer का evidence रिकॉर्ड करें: request और response, और action से पहले और बाद में चलाई गई query व उसका result। Bug report में record की primary key, exact query और लौटाई गई rows लिखें, personal data mask करके, ताकि developer अंदाज़ा लगाने की बजाय वही query दोबारा चला सके।

अभ्यास

Saved addresses के लिए CRUD checks plan करें

आपका काम

एक online shop customers को delivery addresses save करने देता है (material नीचे है)। हर CRUD operation के लिए UI action, अपेक्षित HTTP request, संभावित SQL statement, और product के ज़रिए action करने के बाद database में चलाने लायक कम से कम दो checks लिखें। फिर product owner या developer के लिए एक सवाल लिखें।

सामग्री
Feature: saved delivery addresses
- Customer address जोड़ सकता है, list देख सकता है, address edit कर सकता है
  और address हटा सकता है।
- Customer के addresses में से ठीक एक address default होता है।
- Default address हटाने पर बचे हुए addresses में सबसे हाल में जोड़ा गया
  address default बन जाता है।
- Orders address की अपनी copy रखते हैं; address हटाने से पुराने orders
  नहीं बदलने चाहिए।

Table: addresses
  id, customer_id, label, city, street, is_default,
  created_at, updated_at, deleted_at
  (address active रहने तक deleted_at NULL रहता है)
चरण
  1. चारों operations और हर एक का UI action लिखें।
  2. REST convention के हिसाब से हर एक का HTTP method और path लिखें।
  3. संभावित SQL statement लिखें; table design से पहचानें कि कहाँ delete एक साधारण DELETE नहीं है।
  4. Database checks लिखें, target row के आस-पास की rows समेत।
मॉडल उत्तर दिखाएँ
मॉडल उत्तर

Create: "Add address" → POST /addresses → INSERT INTO addresses। Check: इस customer_id के लिए ठीक एक नई row, हर field सही column में (Arabic text सही), created_at set, deleted_at NULL, और अब भी ठीक एक default; अगर यह customer का पहला address है, तो वही default होना चाहिए।

Read: address list → GET /addresses → SELECT ... WHERE customer_id = ... AND deleted_at IS NULL। Check: list इस customer की active rows के बराबर है, न हटाए गए addresses, न दूसरे customers के।

Update: "Edit" → PATCH /addresses/{id} (या पूरे address के साथ PUT) → UPDATE addresses SET ... WHERE id = ...। Check: सिर्फ़ वही row और edit किए गए columns बदले, updated_at आगे बढ़ा और created_at नहीं बदला; उसे default बनाने पर पिछले default का flag हटता है।

Delete: "Remove" → DELETE /addresses/{id} → ज़्यादा संभावना UPDATE addresses SET deleted_at = ... की, यानी soft delete, क्योंकि table में deleted_at है। Check: row अब भी मौजूद है और deleted_at set है, address list से गायब है, पुराने orders उसे अब भी दिखाते हैं, और अगर वह default था तो सबसे नए created_at वाला active address अब अकेला default है।

सवाल: क्या customer अपना आख़िरी address हटा सकता है? क्या हटाए गए addresses कभी स्थायी रूप से मिटाए जाते हैं, और कब? Edit screen PUT भेजती है या PATCH?

अक्सर पूछे जाने वाले सवाल

क्या CRUD टेस्ट करने के लिए database access ज़रूरी है?

हर check के लिए नहीं। काफ़ी कुछ product के ज़रिए verify हो सकता है: record को किसी दूसरी screen पर या GET से वापस पढ़ें, और उसे किसी दूसरे user के नज़रिए से देखें। लेकिन कुछ असर सिर्फ़ database में दिखते हैं: soft-delete flags, timestamps, related rows, rounding और encoding। Test environment के database का read-only access माँगें; जहाँ यह संभव न हो, developers के साथ तय करें कि ये असर कैसे जाँचे जाएँगे।

क्या soft delete भी delete है?

User के लिए हाँ: record product से गायब हो गया। Database में यह एक UPDATE है जो flag या timestamp set करता है। दोनों पक्ष टेस्ट करें: record lists, search, totals या exports में न दिखे, और row ठीक वैसे रखी जाए या बाद में मिटाई जाए जैसा requirement और कोई data-retention नियम कहता है।

क्या हर API CRUD को POST, GET, PUT, PATCH और DELETE से map करता है?

नहीं। यह REST convention है, जो RFC 9110 और RFC 5789 में methods के अर्थ पर बना है। कई APIs actions को POST requests के रूप में रखते हैं, जैसे POST /orders/42/cancel, और GraphQL APIs आम तौर पर हर operation POST से भेजते हैं। असली mapping API contract बताता है; आपके tests data पर असर जाँचते हैं, method चाहे जो हो।

संदर्भ

  • RFC 9110: HTTP SemanticsIETF · 2022HTTP मेथड, हेडर फ़ील्ड, स्टेटस कोड और कंटेंट निगोशिएशन के अर्थ, वायर वर्ज़न से स्वतंत्र।
  • ISO/IEC 9075-1:2023 — Information technology — Database languages SQL — Part 1: Framework (SQL/Framework)ISO/IEC · 2023अंतरराष्ट्रीय SQL मानक का framework भाग, जिसे PostgreSQL, MySQL, SQLite आदि की बोलियाँ अलग-अलग हद तक लागू करती हैं।
  • SQL As Understood By SQLiteSQLiteSQLite द्वारा स्वीकृत SQL व्याकरण, स्टेटमेंट दर स्टेटमेंट, सिंटैक्स डायग्राम के साथ।
  • RFC 5789: PATCH Method for HTTPIETF · 2010आंशिक अपडेट के लिए PATCH मेथड, जबकि PUT पूरे रिसोर्स को बदल देता है।

Mutqan tools से अभ्यास करें

method, हेडर और JSON बॉडी पर पूरे नियंत्रण के साथ REST endpoint टेस्ट करें, फिर स्टेटस, हेडर और JSON path पर assertion लगाएँ।

API टेस्टिंग

दो JSON डॉक्यूमेंट की सिमैंटिक तुलना करें और जोड़ी गई, हटाई गई तथा बदली गई वैल्यू हाइलाइट करें।

JSON और डेटा

SQL स्टेटमेंट में सिंटैक्स की समस्याएँ, असंतुलित कोष्ठक, बिना बंद की स्ट्रिंग और जोखिम भरे पैटर्न जाँचें।

डेटाबेस

SQL क्वेरी को एकसमान कीवर्ड केसिंग, इंडेंटेशन और लाइन ब्रेक के साथ फ़ॉर्मेट करें (MySQL, PostgreSQL, SQL Server, Oracle, SQLite)।

डेटाबेस

टेबल परिभाषा, नमूना पंक्तियों, CSV या JSON से INSERT स्टेटमेंट बनाएँ।

डेटाबेस

और गहराई से

इस topic में आपकी प्रगति

QA रोडमैप का हिस्सा