actualizare
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -24,3 +24,4 @@ settings.ini
|
|||||||
vfp/settings.ini
|
vfp/settings.ini
|
||||||
vfp/output/
|
vfp/output/
|
||||||
vfp/*.json
|
vfp/*.json
|
||||||
|
*.~pck
|
||||||
|
|||||||
75
SPECIFICATIE_CONTRACT.txt
Normal file
75
SPECIFICATIE_CONTRACT.txt
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
SPECIFICATIE PROIECT - IMPORT COMENZI WEB IN ROA ORACLE
|
||||||
|
Data: 5 martie 2026
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
DESCRIERE SCOP
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
Implementarea unui sistem automat de import a comenzilor de pe platforme web
|
||||||
|
(GoMag si altele) in sistemul ERP ROA Oracle. Sistemul va prelua comenzi,
|
||||||
|
va realiza mapari de articole, va converte unitati de masura si va crea
|
||||||
|
comenzi in ROA automat.
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
DELIVERABLES
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
1. Logica de import completa in baza de date ROA Oracle
|
||||||
|
2. Orchestrator automat (cron job) pentru sincronizare comenzi
|
||||||
|
3. Interfata web de configurare mapari SKU-uri
|
||||||
|
4. Suport pentru articole compuse (mapari complexe)
|
||||||
|
5. Conversii unitati de masura intre platforme
|
||||||
|
6. Documentatie tehnica si handover
|
||||||
|
7. Support 3 luni pentru bug fixes
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
EFORTURI SI COSTURI
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
Lucrat deja: 20h 1,200 EUR
|
||||||
|
De lucrat: 60h 3,600 EUR
|
||||||
|
Support 3 luni: 24h 1,440 EUR
|
||||||
|
|
||||||
|
TOTAL IMPLEMENTARE: 80h 4,800 EUR
|
||||||
|
TOTAL CU SUPPORT: 104h 6,240 EUR
|
||||||
|
|
||||||
|
Tarif orar: 60 EUR/h
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
INCLUS IN PRET
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
- Analiza si integrare cu baza de date client
|
||||||
|
- Testare completa cu date reale
|
||||||
|
- Integrare in sistemul ROA Oracle
|
||||||
|
- Validari si controale de integritate
|
||||||
|
- Documentation si training
|
||||||
|
- Support de 3 luni pentru probleme critice
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
CONDITII GENERALE
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
Duratie proiect: 2-4 saptamani
|
||||||
|
Payment terms: 50% avans, 50% la finalizare
|
||||||
|
Garantie: 3 luni (bug fixes gratuit)
|
||||||
|
Suport suplimentar: 60 EUR/h (dupa perioada garantie)
|
||||||
|
|
||||||
|
Buffer estimare: 50% (pentru integrare ROA + incertitudini)
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
RESPONSABILITATI CLIENT
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
- Acces la baza de date client si ROA Oracle
|
||||||
|
- Accesul la comenzile din platforma web
|
||||||
|
- Clarificarea logicii maparii articole compuse
|
||||||
|
- Testing si validare in mediu pilot
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
@@ -1,40 +1,35 @@
|
|||||||
-- ====================================================================
|
|
||||||
-- P1-004: Package PACK_JSON pentru parsing JSON generic
|
|
||||||
-- Sistem Import Comenzi Web → ROA
|
|
||||||
-- ====================================================================
|
|
||||||
|
|
||||||
CREATE OR REPLACE PACKAGE PACK_JSON AS
|
CREATE OR REPLACE PACKAGE PACK_JSON AS
|
||||||
|
|
||||||
-- Tipuri pentru lucrul cu JSON
|
-- Tipuri pentru lucrul cu JSON
|
||||||
TYPE t_json_array IS TABLE OF VARCHAR2(4000);
|
TYPE t_json_array IS TABLE OF VARCHAR2(4000);
|
||||||
|
|
||||||
TYPE t_json_key_value IS RECORD (
|
TYPE t_json_key_value IS RECORD (
|
||||||
key_name VARCHAR2(100),
|
key_name VARCHAR2(100),
|
||||||
key_value VARCHAR2(4000),
|
key_value VARCHAR2(4000),
|
||||||
key_type VARCHAR2(20) -- 'STRING', 'NUMBER', 'BOOLEAN', 'NULL'
|
key_type VARCHAR2(20) -- 'STRING', 'NUMBER', 'BOOLEAN', 'NULL'
|
||||||
);
|
);
|
||||||
|
|
||||||
TYPE t_json_object IS TABLE OF t_json_key_value;
|
TYPE t_json_object IS TABLE OF t_json_key_value;
|
||||||
|
|
||||||
-- Proprietate pentru tracking erori
|
-- Proprietate pentru tracking erori
|
||||||
g_last_error VARCHAR2(4000);
|
g_last_error VARCHAR2(4000);
|
||||||
|
|
||||||
-- Functie pentru accesarea ultimei erori
|
-- Functie pentru accesarea ultimei erori
|
||||||
FUNCTION get_last_error RETURN VARCHAR2;
|
FUNCTION get_last_error RETURN VARCHAR2;
|
||||||
|
|
||||||
-- Functie pentru resetarea erorii
|
-- Functie pentru resetarea erorii
|
||||||
PROCEDURE clear_error;
|
PROCEDURE clear_error;
|
||||||
|
|
||||||
-- Main parsing functions
|
-- Main parsing functions
|
||||||
FUNCTION parse_array(p_json_array IN CLOB) RETURN t_json_array PIPELINED; -- Parse [{"a":1},{"b":2}]
|
FUNCTION parse_array(p_json_array IN CLOB) RETURN t_json_array PIPELINED; -- Parse [{"a":1},{"b":2}]
|
||||||
FUNCTION get_string(p_json_object IN VARCHAR2, p_key_name IN VARCHAR2) RETURN VARCHAR2; -- Get "value"
|
FUNCTION get_string(p_json_object IN VARCHAR2, p_key_name IN VARCHAR2) RETURN VARCHAR2; -- Get "value"
|
||||||
FUNCTION get_number(p_json_object IN VARCHAR2, p_key_name IN VARCHAR2) RETURN NUMBER; -- Get 123.45
|
FUNCTION get_number(p_json_object IN VARCHAR2, p_key_name IN VARCHAR2) RETURN NUMBER; -- Get 123.45
|
||||||
FUNCTION get_boolean(p_json_object IN VARCHAR2, p_key_name IN VARCHAR2) RETURN BOOLEAN; -- Get true/false
|
FUNCTION get_boolean(p_json_object IN VARCHAR2, p_key_name IN VARCHAR2) RETURN BOOLEAN; -- Get true/false
|
||||||
|
|
||||||
-- Advanced functions
|
-- Advanced functions
|
||||||
FUNCTION parse_object(p_json_object IN VARCHAR2) RETURN t_json_object PIPELINED; -- Parse to key-value pairs
|
FUNCTION parse_object(p_json_object IN VARCHAR2) RETURN t_json_object PIPELINED; -- Parse to key-value pairs
|
||||||
FUNCTION clean(p_json IN CLOB) RETURN CLOB; -- Remove whitespace/formatting
|
FUNCTION clean(p_json IN CLOB) RETURN CLOB; -- Remove whitespace/formatting
|
||||||
|
|
||||||
-- Test functions
|
-- Test functions
|
||||||
PROCEDURE run_tests; -- Run all built-in tests
|
PROCEDURE run_tests; -- Run all built-in tests
|
||||||
FUNCTION test_basic_parsing RETURN VARCHAR2; -- Test basic JSON parsing
|
FUNCTION test_basic_parsing RETURN VARCHAR2; -- Test basic JSON parsing
|
||||||
@@ -44,10 +39,6 @@ CREATE OR REPLACE PACKAGE PACK_JSON AS
|
|||||||
|
|
||||||
END PACK_JSON;
|
END PACK_JSON;
|
||||||
/
|
/
|
||||||
|
|
||||||
-- ====================================================================
|
|
||||||
-- Package Body - Implementarea functiilor
|
|
||||||
-- ====================================================================
|
|
||||||
CREATE OR REPLACE PACKAGE BODY PACK_JSON AS
|
CREATE OR REPLACE PACKAGE BODY PACK_JSON AS
|
||||||
/*
|
/*
|
||||||
PACK_JSON - Generic JSON Parser (Oracle 10g/11g/12c compatible)
|
PACK_JSON - Generic JSON Parser (Oracle 10g/11g/12c compatible)
|
||||||
@@ -57,12 +48,12 @@ USAGE:
|
|||||||
FOR obj IN (SELECT * FROM TABLE(PACK_JSON.parse_array(json_clob))) LOOP
|
FOR obj IN (SELECT * FROM TABLE(PACK_JSON.parse_array(json_clob))) LOOP
|
||||||
v_val := PACK_JSON.get_string(obj.COLUMN_VALUE, 'key');
|
v_val := PACK_JSON.get_string(obj.COLUMN_VALUE, 'key');
|
||||||
END LOOP;
|
END LOOP;
|
||||||
|
|
||||||
-- Get values from object: {"name":"John","age":25,"active":true}
|
-- Get values from object: {"name":"John","age":25,"active":true}
|
||||||
v_name := PACK_JSON.get_string(json_obj, 'name'); -- Returns: John
|
v_name := PACK_JSON.get_string(json_obj, 'name'); -- Returns: John
|
||||||
v_age := PACK_JSON.get_number(json_obj, 'age'); -- Returns: 25
|
v_age := PACK_JSON.get_number(json_obj, 'age'); -- Returns: 25
|
||||||
v_active := PACK_JSON.get_boolean(json_obj, 'active'); -- Returns: TRUE
|
v_active := PACK_JSON.get_boolean(json_obj, 'active'); -- Returns: TRUE
|
||||||
|
|
||||||
-- Error handling:
|
-- Error handling:
|
||||||
IF PACK_JSON.get_last_error() IS NOT NULL THEN
|
IF PACK_JSON.get_last_error() IS NOT NULL THEN
|
||||||
-- Handle error: PACK_JSON.get_last_error()
|
-- Handle error: PACK_JSON.get_last_error()
|
||||||
@@ -72,7 +63,7 @@ USAGE:
|
|||||||
FUNCTIONS:
|
FUNCTIONS:
|
||||||
parse_array(clob) - Parse JSON array, returns table of objects
|
parse_array(clob) - Parse JSON array, returns table of objects
|
||||||
get_string(obj,key) - Extract string value from JSON object
|
get_string(obj,key) - Extract string value from JSON object
|
||||||
get_number(obj,key) - Extract number value from JSON object
|
get_number(obj,key) - Extract number value from JSON object
|
||||||
get_boolean(obj,key) - Extract boolean value from JSON object
|
get_boolean(obj,key) - Extract boolean value from JSON object
|
||||||
get_last_error() - Get last parsing error (NULL if no error)
|
get_last_error() - Get last parsing error (NULL if no error)
|
||||||
clear_error() - Clear error state
|
clear_error() - Clear error state
|
||||||
@@ -85,7 +76,7 @@ FUNCTIONS:
|
|||||||
BEGIN
|
BEGIN
|
||||||
RETURN g_last_error;
|
RETURN g_last_error;
|
||||||
END get_last_error;
|
END get_last_error;
|
||||||
|
|
||||||
PROCEDURE clear_error IS
|
PROCEDURE clear_error IS
|
||||||
BEGIN
|
BEGIN
|
||||||
g_last_error := NULL;
|
g_last_error := NULL;
|
||||||
@@ -100,9 +91,9 @@ FUNCTIONS:
|
|||||||
v_clean CLOB;
|
v_clean CLOB;
|
||||||
BEGIN
|
BEGIN
|
||||||
-- Elimina spatii, tab-uri, newline-uri pentru parsing mai usor
|
-- Elimina spatii, tab-uri, newline-uri pentru parsing mai usor
|
||||||
v_clean := REPLACE(REPLACE(REPLACE(REPLACE(p_json,
|
v_clean := REPLACE(REPLACE(REPLACE(REPLACE(p_json,
|
||||||
CHR(10), ''), CHR(13), ''), CHR(9), ''), ' ', '');
|
CHR(10), ''), CHR(13), ''), CHR(9), ''), ' ', '');
|
||||||
|
|
||||||
RETURN v_clean;
|
RETURN v_clean;
|
||||||
END clean;
|
END clean;
|
||||||
|
|
||||||
@@ -112,50 +103,50 @@ FUNCTIONS:
|
|||||||
FUNCTION parse_array(
|
FUNCTION parse_array(
|
||||||
p_json_array IN CLOB
|
p_json_array IN CLOB
|
||||||
) RETURN t_json_array PIPELINED IS
|
) RETURN t_json_array PIPELINED IS
|
||||||
|
|
||||||
v_json_clean CLOB;
|
v_json_clean CLOB;
|
||||||
v_articol_json VARCHAR2(4000);
|
v_articol_json VARCHAR2(4000);
|
||||||
v_start_pos NUMBER := 1;
|
v_start_pos NUMBER := 1;
|
||||||
v_end_pos NUMBER;
|
v_end_pos NUMBER;
|
||||||
v_bracket_count NUMBER;
|
v_bracket_count NUMBER;
|
||||||
|
|
||||||
BEGIN
|
BEGIN
|
||||||
-- Reset error
|
-- Reset error
|
||||||
g_last_error := NULL;
|
g_last_error := NULL;
|
||||||
|
|
||||||
-- Curata JSON-ul
|
-- Curata JSON-ul
|
||||||
v_json_clean := clean(p_json_array);
|
v_json_clean := clean(p_json_array);
|
||||||
|
|
||||||
-- Elimina bracket-urile exterioare [ ]
|
-- Elimina bracket-urile exterioare [ ]
|
||||||
v_json_clean := TRIM(BOTH '[]' FROM v_json_clean);
|
v_json_clean := TRIM(BOTH '[]' FROM v_json_clean);
|
||||||
|
|
||||||
-- Parse fiecare obiect JSON din array
|
-- Parse fiecare obiect JSON din array
|
||||||
LOOP
|
LOOP
|
||||||
-- Gaseste inceputul obiectului JSON {
|
-- Gaseste inceputul obiectului JSON {
|
||||||
v_start_pos := INSTR(v_json_clean, '{', v_start_pos);
|
v_start_pos := INSTR(v_json_clean, '{', v_start_pos);
|
||||||
EXIT WHEN v_start_pos = 0;
|
EXIT WHEN v_start_pos = 0;
|
||||||
|
|
||||||
-- Gaseste sfarsitul obiectului JSON } - ia in considerare nested objects
|
-- Gaseste sfarsitul obiectului JSON } - ia in considerare nested objects
|
||||||
v_bracket_count := 1;
|
v_bracket_count := 1;
|
||||||
v_end_pos := v_start_pos;
|
v_end_pos := v_start_pos;
|
||||||
|
|
||||||
WHILE v_bracket_count > 0 AND v_end_pos < LENGTH(v_json_clean) LOOP
|
WHILE v_bracket_count > 0 AND v_end_pos < LENGTH(v_json_clean) LOOP
|
||||||
v_end_pos := v_end_pos + 1;
|
v_end_pos := v_end_pos + 1;
|
||||||
|
|
||||||
IF SUBSTR(v_json_clean, v_end_pos, 1) = '{' THEN
|
IF SUBSTR(v_json_clean, v_end_pos, 1) = '{' THEN
|
||||||
v_bracket_count := v_bracket_count + 1;
|
v_bracket_count := v_bracket_count + 1;
|
||||||
ELSIF SUBSTR(v_json_clean, v_end_pos, 1) = '}' THEN
|
ELSIF SUBSTR(v_json_clean, v_end_pos, 1) = '}' THEN
|
||||||
v_bracket_count := v_bracket_count - 1;
|
v_bracket_count := v_bracket_count - 1;
|
||||||
END IF;
|
END IF;
|
||||||
END LOOP;
|
END LOOP;
|
||||||
|
|
||||||
-- Extrage obiectul JSON curent
|
-- Extrage obiectul JSON curent
|
||||||
IF v_bracket_count = 0 THEN
|
IF v_bracket_count = 0 THEN
|
||||||
v_articol_json := SUBSTR(v_json_clean, v_start_pos, v_end_pos - v_start_pos + 1);
|
v_articol_json := SUBSTR(v_json_clean, v_start_pos, v_end_pos - v_start_pos + 1);
|
||||||
|
|
||||||
|
|
||||||
PIPE ROW(v_articol_json);
|
PIPE ROW(v_articol_json);
|
||||||
|
|
||||||
-- Trece la urmatorul articol
|
-- Trece la urmatorul articol
|
||||||
v_start_pos := v_end_pos + 1;
|
v_start_pos := v_end_pos + 1;
|
||||||
ELSE
|
ELSE
|
||||||
@@ -164,8 +155,8 @@ FUNCTIONS:
|
|||||||
EXIT;
|
EXIT;
|
||||||
END IF;
|
END IF;
|
||||||
END LOOP;
|
END LOOP;
|
||||||
|
|
||||||
|
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN OTHERS THEN
|
WHEN OTHERS THEN
|
||||||
g_last_error := 'Eroare la parsing array: ' || SQLERRM;
|
g_last_error := 'Eroare la parsing array: ' || SQLERRM;
|
||||||
@@ -181,16 +172,16 @@ FUNCTIONS:
|
|||||||
v_result VARCHAR2(4000);
|
v_result VARCHAR2(4000);
|
||||||
BEGIN
|
BEGIN
|
||||||
-- Oracle 10g compatible: Extract string values
|
-- Oracle 10g compatible: Extract string values
|
||||||
v_result := REGEXP_SUBSTR(p_json_object,
|
v_result := REGEXP_SUBSTR(p_json_object,
|
||||||
'"' || p_key_name || '":"[^"]*"');
|
'"' || p_key_name || '":"[^"]*"');
|
||||||
IF v_result IS NOT NULL THEN
|
IF v_result IS NOT NULL THEN
|
||||||
-- Remove key part and quotes manually
|
-- Remove key part and quotes manually
|
||||||
v_result := REGEXP_REPLACE(v_result, '^"' || p_key_name || '":"', '');
|
v_result := REGEXP_REPLACE(v_result, '^"' || p_key_name || '":"', '');
|
||||||
v_result := REGEXP_REPLACE(v_result, '"$', '');
|
v_result := REGEXP_REPLACE(v_result, '"$', '');
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
RETURN v_result;
|
RETURN v_result;
|
||||||
|
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN OTHERS THEN
|
WHEN OTHERS THEN
|
||||||
g_last_error := 'Eroare la extragere string pentru ' || p_key_name || ': ' || SQLERRM;
|
g_last_error := 'Eroare la extragere string pentru ' || p_key_name || ': ' || SQLERRM;
|
||||||
@@ -209,23 +200,23 @@ FUNCTIONS:
|
|||||||
BEGIN
|
BEGIN
|
||||||
-- Oracle 10g compatible: Extract number values without subexpressions
|
-- Oracle 10g compatible: Extract number values without subexpressions
|
||||||
-- Pattern: "key_name":123.45 (numeric value direct)
|
-- Pattern: "key_name":123.45 (numeric value direct)
|
||||||
v_result_str := REGEXP_SUBSTR(p_json_object,
|
v_result_str := REGEXP_SUBSTR(p_json_object,
|
||||||
'"' || p_key_name || '":[0-9]+\.?[0-9]*');
|
'"' || p_key_name || '":[0-9]+\.?[0-9]*');
|
||||||
IF v_result_str IS NOT NULL THEN
|
IF v_result_str IS NOT NULL THEN
|
||||||
-- Extract just the number part after the colon
|
-- Extract just the number part after the colon
|
||||||
v_result_str := REGEXP_SUBSTR(v_result_str, '[0-9]+\.?[0-9]*');
|
v_result_str := REGEXP_SUBSTR(v_result_str, '[0-9]+\.?[0-9]*');
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
-- Daca nu gaseste, incearca cu quotes: "key_name":"123.45"
|
-- Daca nu gaseste, incearca cu quotes: "key_name":"123.45"
|
||||||
IF v_result_str IS NULL OR LENGTH(TRIM(v_result_str)) = 0 THEN
|
IF v_result_str IS NULL OR LENGTH(TRIM(v_result_str)) = 0 THEN
|
||||||
v_result_str := REGEXP_SUBSTR(p_json_object,
|
v_result_str := REGEXP_SUBSTR(p_json_object,
|
||||||
'"' || p_key_name || '":"[0-9]+\.?[0-9]*"');
|
'"' || p_key_name || '":"[0-9]+\.?[0-9]*"');
|
||||||
IF v_result_str IS NOT NULL THEN
|
IF v_result_str IS NOT NULL THEN
|
||||||
-- Extract number between quotes
|
-- Extract number between quotes
|
||||||
v_result_str := REGEXP_SUBSTR(v_result_str, '[0-9]+\.?[0-9]*');
|
v_result_str := REGEXP_SUBSTR(v_result_str, '[0-9]+\.?[0-9]*');
|
||||||
END IF;
|
END IF;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
IF v_result_str IS NOT NULL AND LENGTH(TRIM(v_result_str)) > 0 THEN
|
IF v_result_str IS NOT NULL AND LENGTH(TRIM(v_result_str)) > 0 THEN
|
||||||
BEGIN
|
BEGIN
|
||||||
v_result_str := TRIM(v_result_str);
|
v_result_str := TRIM(v_result_str);
|
||||||
@@ -243,9 +234,9 @@ FUNCTIONS:
|
|||||||
END;
|
END;
|
||||||
END;
|
END;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
RETURN v_result;
|
RETURN v_result;
|
||||||
|
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN OTHERS THEN
|
WHEN OTHERS THEN
|
||||||
g_last_error := 'Eroare la extragere number pentru ' || p_key_name || ': ' || SQLERRM;
|
g_last_error := 'Eroare la extragere number pentru ' || p_key_name || ': ' || SQLERRM;
|
||||||
@@ -262,13 +253,13 @@ FUNCTIONS:
|
|||||||
v_result_str VARCHAR2(100);
|
v_result_str VARCHAR2(100);
|
||||||
BEGIN
|
BEGIN
|
||||||
-- Oracle 10g compatible: Extract boolean values
|
-- Oracle 10g compatible: Extract boolean values
|
||||||
v_result_str := REGEXP_SUBSTR(p_json_object,
|
v_result_str := REGEXP_SUBSTR(p_json_object,
|
||||||
'"' || p_key_name || '":(true|false)');
|
'"' || p_key_name || '":(true|false)');
|
||||||
IF v_result_str IS NOT NULL THEN
|
IF v_result_str IS NOT NULL THEN
|
||||||
-- Extract just the boolean value
|
-- Extract just the boolean value
|
||||||
v_result_str := REGEXP_REPLACE(v_result_str, '^"' || p_key_name || '":', '');
|
v_result_str := REGEXP_REPLACE(v_result_str, '^"' || p_key_name || '":', '');
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
IF v_result_str = 'true' THEN
|
IF v_result_str = 'true' THEN
|
||||||
RETURN TRUE;
|
RETURN TRUE;
|
||||||
ELSIF v_result_str = 'false' THEN
|
ELSIF v_result_str = 'false' THEN
|
||||||
@@ -276,7 +267,7 @@ FUNCTIONS:
|
|||||||
ELSE
|
ELSE
|
||||||
RETURN NULL;
|
RETURN NULL;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN OTHERS THEN
|
WHEN OTHERS THEN
|
||||||
g_last_error := 'Eroare la extragere boolean pentru ' || p_key_name || ': ' || SQLERRM;
|
g_last_error := 'Eroare la extragere boolean pentru ' || p_key_name || ': ' || SQLERRM;
|
||||||
@@ -289,7 +280,7 @@ FUNCTIONS:
|
|||||||
FUNCTION parse_object(
|
FUNCTION parse_object(
|
||||||
p_json_object IN VARCHAR2
|
p_json_object IN VARCHAR2
|
||||||
) RETURN t_json_object PIPELINED IS
|
) RETURN t_json_object PIPELINED IS
|
||||||
|
|
||||||
v_clean_json VARCHAR2(4000);
|
v_clean_json VARCHAR2(4000);
|
||||||
v_key VARCHAR2(100);
|
v_key VARCHAR2(100);
|
||||||
v_value VARCHAR2(4000);
|
v_value VARCHAR2(4000);
|
||||||
@@ -299,27 +290,27 @@ FUNCTIONS:
|
|||||||
v_key_end NUMBER;
|
v_key_end NUMBER;
|
||||||
v_value_start NUMBER;
|
v_value_start NUMBER;
|
||||||
v_value_end NUMBER;
|
v_value_end NUMBER;
|
||||||
|
|
||||||
BEGIN
|
BEGIN
|
||||||
-- Curata JSON-ul si elimina { }
|
-- Curata JSON-ul si elimina { }
|
||||||
v_clean_json := TRIM(BOTH '{}' FROM REPLACE(p_json_object, ' ', ''));
|
v_clean_json := TRIM(BOTH '{}' FROM REPLACE(p_json_object, ' ', ''));
|
||||||
|
|
||||||
-- Parse fiecare pereche key:value
|
-- Parse fiecare pereche key:value
|
||||||
WHILE v_pos < LENGTH(v_clean_json) LOOP
|
WHILE v_pos < LENGTH(v_clean_json) LOOP
|
||||||
-- Gaseste cheia
|
-- Gaseste cheia
|
||||||
v_key_start := INSTR(v_clean_json, '"', v_pos);
|
v_key_start := INSTR(v_clean_json, '"', v_pos);
|
||||||
EXIT WHEN v_key_start = 0;
|
EXIT WHEN v_key_start = 0;
|
||||||
|
|
||||||
v_key_end := INSTR(v_clean_json, '"', v_key_start + 1);
|
v_key_end := INSTR(v_clean_json, '"', v_key_start + 1);
|
||||||
EXIT WHEN v_key_end = 0;
|
EXIT WHEN v_key_end = 0;
|
||||||
|
|
||||||
v_key := SUBSTR(v_clean_json, v_key_start + 1, v_key_end - v_key_start - 1);
|
v_key := SUBSTR(v_clean_json, v_key_start + 1, v_key_end - v_key_start - 1);
|
||||||
|
|
||||||
-- Gaseste valoarea
|
-- Gaseste valoarea
|
||||||
v_value_start := INSTR(v_clean_json, ':', v_key_end);
|
v_value_start := INSTR(v_clean_json, ':', v_key_end);
|
||||||
EXIT WHEN v_value_start = 0;
|
EXIT WHEN v_value_start = 0;
|
||||||
v_value_start := v_value_start + 1;
|
v_value_start := v_value_start + 1;
|
||||||
|
|
||||||
-- Determina tipul si extrage valoarea
|
-- Determina tipul si extrage valoarea
|
||||||
IF SUBSTR(v_clean_json, v_value_start, 1) = '"' THEN
|
IF SUBSTR(v_clean_json, v_value_start, 1) = '"' THEN
|
||||||
-- String value
|
-- String value
|
||||||
@@ -331,7 +322,7 @@ FUNCTIONS:
|
|||||||
-- Number, boolean sau null
|
-- Number, boolean sau null
|
||||||
v_value_end := NVL(INSTR(v_clean_json, ',', v_value_start), LENGTH(v_clean_json) + 1);
|
v_value_end := NVL(INSTR(v_clean_json, ',', v_value_start), LENGTH(v_clean_json) + 1);
|
||||||
v_value := SUBSTR(v_clean_json, v_value_start, v_value_end - v_value_start);
|
v_value := SUBSTR(v_clean_json, v_value_start, v_value_end - v_value_start);
|
||||||
|
|
||||||
IF v_value IN ('true', 'false') THEN
|
IF v_value IN ('true', 'false') THEN
|
||||||
v_result.key_type := 'BOOLEAN';
|
v_result.key_type := 'BOOLEAN';
|
||||||
ELSIF v_value = 'null' THEN
|
ELSIF v_value = 'null' THEN
|
||||||
@@ -341,16 +332,16 @@ FUNCTIONS:
|
|||||||
ELSE
|
ELSE
|
||||||
v_result.key_type := 'UNKNOWN';
|
v_result.key_type := 'UNKNOWN';
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
v_pos := v_value_end + 1;
|
v_pos := v_value_end + 1;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
v_result.key_name := v_key;
|
v_result.key_name := v_key;
|
||||||
v_result.key_value := v_value;
|
v_result.key_value := v_value;
|
||||||
|
|
||||||
PIPE ROW(v_result);
|
PIPE ROW(v_result);
|
||||||
END LOOP;
|
END LOOP;
|
||||||
|
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN OTHERS THEN
|
WHEN OTHERS THEN
|
||||||
g_last_error := 'Eroare la parsing obiect: ' || SQLERRM;
|
g_last_error := 'Eroare la parsing obiect: ' || SQLERRM;
|
||||||
@@ -359,7 +350,7 @@ FUNCTIONS:
|
|||||||
-- ================================================================
|
-- ================================================================
|
||||||
-- Functii de testare
|
-- Functii de testare
|
||||||
-- ================================================================
|
-- ================================================================
|
||||||
|
|
||||||
FUNCTION test_basic_parsing RETURN VARCHAR2 IS
|
FUNCTION test_basic_parsing RETURN VARCHAR2 IS
|
||||||
v_test_json VARCHAR2(1000) := '{"name":"John","age":25,"active":true,"score":98.5}';
|
v_test_json VARCHAR2(1000) := '{"name":"John","age":25,"active":true,"score":98.5}';
|
||||||
v_name VARCHAR2(100);
|
v_name VARCHAR2(100);
|
||||||
@@ -369,29 +360,29 @@ FUNCTIONS:
|
|||||||
v_result VARCHAR2(4000) := 'BASIC_PARSING: ';
|
v_result VARCHAR2(4000) := 'BASIC_PARSING: ';
|
||||||
BEGIN
|
BEGIN
|
||||||
clear_error();
|
clear_error();
|
||||||
|
|
||||||
v_name := get_string(v_test_json, 'name');
|
v_name := get_string(v_test_json, 'name');
|
||||||
v_age := get_number(v_test_json, 'age');
|
v_age := get_number(v_test_json, 'age');
|
||||||
v_active := get_boolean(v_test_json, 'active');
|
v_active := get_boolean(v_test_json, 'active');
|
||||||
v_score := get_number(v_test_json, 'score');
|
v_score := get_number(v_test_json, 'score');
|
||||||
|
|
||||||
-- Validate results
|
-- Validate results
|
||||||
IF v_name = 'John' AND v_age = 25 AND v_active = TRUE AND v_score = 98.5 THEN
|
IF v_name = 'John' AND v_age = 25 AND v_active = TRUE AND v_score = 98.5 THEN
|
||||||
v_result := v_result || 'PASS - All values extracted correctly';
|
v_result := v_result || 'PASS - All values extracted correctly';
|
||||||
ELSE
|
ELSE
|
||||||
v_result := v_result || 'FAIL - Values: name=' || v_name || ', age=' || v_age || ', score=' || v_score;
|
v_result := v_result || 'FAIL - Values: name=' || v_name || ', age=' || v_age || ', score=' || v_score;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
IF get_last_error() IS NOT NULL THEN
|
IF get_last_error() IS NOT NULL THEN
|
||||||
v_result := v_result || ' ERROR: ' || get_last_error();
|
v_result := v_result || ' ERROR: ' || get_last_error();
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
RETURN v_result;
|
RETURN v_result;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN OTHERS THEN
|
WHEN OTHERS THEN
|
||||||
RETURN 'BASIC_PARSING: EXCEPTION - ' || SQLERRM;
|
RETURN 'BASIC_PARSING: EXCEPTION - ' || SQLERRM;
|
||||||
END test_basic_parsing;
|
END test_basic_parsing;
|
||||||
|
|
||||||
FUNCTION test_array_parsing RETURN VARCHAR2 IS
|
FUNCTION test_array_parsing RETURN VARCHAR2 IS
|
||||||
v_test_array CLOB := '[{"sku":"PROD1","price":10.5},{"sku":"PROD2","price":25.0}]';
|
v_test_array CLOB := '[{"sku":"PROD1","price":10.5},{"sku":"PROD2","price":25.0}]';
|
||||||
v_count NUMBER := 0;
|
v_count NUMBER := 0;
|
||||||
@@ -400,12 +391,12 @@ FUNCTIONS:
|
|||||||
v_result VARCHAR2(4000) := 'ARRAY_PARSING: ';
|
v_result VARCHAR2(4000) := 'ARRAY_PARSING: ';
|
||||||
BEGIN
|
BEGIN
|
||||||
clear_error();
|
clear_error();
|
||||||
|
|
||||||
FOR obj IN (SELECT * FROM TABLE(parse_array(v_test_array))) LOOP
|
FOR obj IN (SELECT * FROM TABLE(parse_array(v_test_array))) LOOP
|
||||||
v_count := v_count + 1;
|
v_count := v_count + 1;
|
||||||
v_sku := get_string(obj.COLUMN_VALUE, 'sku');
|
v_sku := get_string(obj.COLUMN_VALUE, 'sku');
|
||||||
v_price := get_number(obj.COLUMN_VALUE, 'price');
|
v_price := get_number(obj.COLUMN_VALUE, 'price');
|
||||||
|
|
||||||
IF v_count = 1 THEN
|
IF v_count = 1 THEN
|
||||||
IF v_sku != 'PROD1' OR v_price != 10.5 THEN
|
IF v_sku != 'PROD1' OR v_price != 10.5 THEN
|
||||||
RETURN v_result || 'FAIL - First object: sku=' || v_sku || ', price=' || v_price;
|
RETURN v_result || 'FAIL - First object: sku=' || v_sku || ', price=' || v_price;
|
||||||
@@ -416,23 +407,23 @@ FUNCTIONS:
|
|||||||
END IF;
|
END IF;
|
||||||
END IF;
|
END IF;
|
||||||
END LOOP;
|
END LOOP;
|
||||||
|
|
||||||
IF v_count = 2 THEN
|
IF v_count = 2 THEN
|
||||||
v_result := v_result || 'PASS - Parsed ' || v_count || ' objects correctly';
|
v_result := v_result || 'PASS - Parsed ' || v_count || ' objects correctly';
|
||||||
ELSE
|
ELSE
|
||||||
v_result := v_result || 'FAIL - Expected 2 objects, got ' || v_count;
|
v_result := v_result || 'FAIL - Expected 2 objects, got ' || v_count;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
IF get_last_error() IS NOT NULL THEN
|
IF get_last_error() IS NOT NULL THEN
|
||||||
v_result := v_result || ' ERROR: ' || get_last_error();
|
v_result := v_result || ' ERROR: ' || get_last_error();
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
RETURN v_result;
|
RETURN v_result;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN OTHERS THEN
|
WHEN OTHERS THEN
|
||||||
RETURN 'ARRAY_PARSING: EXCEPTION - ' || SQLERRM;
|
RETURN 'ARRAY_PARSING: EXCEPTION - ' || SQLERRM;
|
||||||
END test_array_parsing;
|
END test_array_parsing;
|
||||||
|
|
||||||
FUNCTION test_nested_objects RETURN VARCHAR2 IS
|
FUNCTION test_nested_objects RETURN VARCHAR2 IS
|
||||||
v_test_nested CLOB := '[{"order":{"id":123,"items":[{"sku":"A1","qty":2}],"total":25.50}},{"order":{"id":124,"items":[{"sku":"B1","qty":1},{"sku":"C1","qty":3}],"total":45.00}}]';
|
v_test_nested CLOB := '[{"order":{"id":123,"items":[{"sku":"A1","qty":2}],"total":25.50}},{"order":{"id":124,"items":[{"sku":"B1","qty":1},{"sku":"C1","qty":3}],"total":45.00}}]';
|
||||||
v_count NUMBER := 0;
|
v_count NUMBER := 0;
|
||||||
@@ -443,16 +434,16 @@ FUNCTIONS:
|
|||||||
v_order_json VARCHAR2(2000);
|
v_order_json VARCHAR2(2000);
|
||||||
BEGIN
|
BEGIN
|
||||||
clear_error();
|
clear_error();
|
||||||
|
|
||||||
-- Test parsing array cu nested objects
|
-- Test parsing array cu nested objects
|
||||||
FOR obj IN (SELECT * FROM TABLE(parse_array(v_test_nested))) LOOP
|
FOR obj IN (SELECT * FROM TABLE(parse_array(v_test_nested))) LOOP
|
||||||
v_count := v_count + 1;
|
v_count := v_count + 1;
|
||||||
v_object := obj.COLUMN_VALUE;
|
v_object := obj.COLUMN_VALUE;
|
||||||
|
|
||||||
-- Extrage nested object "order" (Oracle 10g compatible)
|
-- Extrage nested object "order" (Oracle 10g compatible)
|
||||||
v_order_json := REGEXP_SUBSTR(v_object, '"order":\{[^}]+\}');
|
v_order_json := REGEXP_SUBSTR(v_object, '"order":\{[^}]+\}');
|
||||||
IF v_order_json IS NOT NULL THEN
|
IF v_order_json IS NOT NULL THEN
|
||||||
-- Extract just the object part
|
-- Extract just the object part
|
||||||
v_order_json := REGEXP_REPLACE(v_order_json, '^"order":', '');
|
v_order_json := REGEXP_REPLACE(v_order_json, '^"order":', '');
|
||||||
END IF;
|
END IF;
|
||||||
IF v_order_json IS NULL THEN
|
IF v_order_json IS NULL THEN
|
||||||
@@ -461,11 +452,11 @@ FUNCTIONS:
|
|||||||
-- Elimina "order": din fata
|
-- Elimina "order": din fata
|
||||||
v_order_json := REGEXP_REPLACE(v_order_json, '^"order":', '');
|
v_order_json := REGEXP_REPLACE(v_order_json, '^"order":', '');
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
IF v_order_json IS NOT NULL THEN
|
IF v_order_json IS NOT NULL THEN
|
||||||
v_order_id := get_number(v_order_json, 'id');
|
v_order_id := get_number(v_order_json, 'id');
|
||||||
v_total := get_number(v_order_json, 'total');
|
v_total := get_number(v_order_json, 'total');
|
||||||
|
|
||||||
IF v_count = 1 THEN
|
IF v_count = 1 THEN
|
||||||
IF v_order_id != 123 OR v_total != 25.50 THEN
|
IF v_order_id != 123 OR v_total != 25.50 THEN
|
||||||
RETURN v_result || 'FAIL - First nested: id=' || v_order_id || ', total=' || v_total;
|
RETURN v_result || 'FAIL - First nested: id=' || v_order_id || ', total=' || v_total;
|
||||||
@@ -479,30 +470,30 @@ FUNCTIONS:
|
|||||||
RETURN v_result || 'FAIL - Could not extract nested order object from: ' || SUBSTR(v_object, 1, 100);
|
RETURN v_result || 'FAIL - Could not extract nested order object from: ' || SUBSTR(v_object, 1, 100);
|
||||||
END IF;
|
END IF;
|
||||||
END LOOP;
|
END LOOP;
|
||||||
|
|
||||||
IF v_count = 2 THEN
|
IF v_count = 2 THEN
|
||||||
v_result := v_result || 'PASS - Parsed ' || v_count || ' nested objects correctly';
|
v_result := v_result || 'PASS - Parsed ' || v_count || ' nested objects correctly';
|
||||||
ELSE
|
ELSE
|
||||||
v_result := v_result || 'FAIL - Expected 2 nested objects, got ' || v_count;
|
v_result := v_result || 'FAIL - Expected 2 nested objects, got ' || v_count;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
IF get_last_error() IS NOT NULL THEN
|
IF get_last_error() IS NOT NULL THEN
|
||||||
v_result := v_result || ' ERROR: ' || get_last_error();
|
v_result := v_result || ' ERROR: ' || get_last_error();
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
RETURN v_result;
|
RETURN v_result;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN OTHERS THEN
|
WHEN OTHERS THEN
|
||||||
RETURN 'NESTED_OBJECTS: EXCEPTION - ' || SQLERRM;
|
RETURN 'NESTED_OBJECTS: EXCEPTION - ' || SQLERRM;
|
||||||
END test_nested_objects;
|
END test_nested_objects;
|
||||||
|
|
||||||
FUNCTION test_error_handling RETURN VARCHAR2 IS
|
FUNCTION test_error_handling RETURN VARCHAR2 IS
|
||||||
v_result VARCHAR2(4000) := 'ERROR_HANDLING: ';
|
v_result VARCHAR2(4000) := 'ERROR_HANDLING: ';
|
||||||
v_invalid_json VARCHAR2(1000) := '{"broken":}';
|
v_invalid_json VARCHAR2(1000) := '{"broken":}';
|
||||||
v_value VARCHAR2(100);
|
v_value VARCHAR2(100);
|
||||||
BEGIN
|
BEGIN
|
||||||
clear_error();
|
clear_error();
|
||||||
|
|
||||||
-- Force an error by trying to parse malformed array
|
-- Force an error by trying to parse malformed array
|
||||||
BEGIN
|
BEGIN
|
||||||
FOR obj IN (SELECT * FROM TABLE(parse_array('[{"incomplete":"object"'))) LOOP
|
FOR obj IN (SELECT * FROM TABLE(parse_array('[{"incomplete":"object"'))) LOOP
|
||||||
@@ -513,52 +504,52 @@ FUNCTIONS:
|
|||||||
-- This should trigger parse_array to set g_last_error
|
-- This should trigger parse_array to set g_last_error
|
||||||
NULL;
|
NULL;
|
||||||
END;
|
END;
|
||||||
|
|
||||||
-- Alternative: try to get a string from NULL object
|
-- Alternative: try to get a string from NULL object
|
||||||
v_value := get_string(NULL, 'test');
|
v_value := get_string(NULL, 'test');
|
||||||
|
|
||||||
IF get_last_error() IS NOT NULL THEN
|
IF get_last_error() IS NOT NULL THEN
|
||||||
v_result := v_result || 'PASS - Error properly captured: ' || SUBSTR(get_last_error(), 1, 100);
|
v_result := v_result || 'PASS - Error properly captured: ' || SUBSTR(get_last_error(), 1, 100);
|
||||||
clear_error();
|
clear_error();
|
||||||
ELSE
|
ELSE
|
||||||
v_result := v_result || 'FAIL - No error captured for invalid operations';
|
v_result := v_result || 'FAIL - No error captured for invalid operations';
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
-- Test error clearing
|
-- Test error clearing
|
||||||
IF get_last_error() IS NULL THEN
|
IF get_last_error() IS NULL THEN
|
||||||
v_result := v_result || ' - Error cleared successfully';
|
v_result := v_result || ' - Error cleared successfully';
|
||||||
ELSE
|
ELSE
|
||||||
v_result := v_result || ' - Error not cleared properly';
|
v_result := v_result || ' - Error not cleared properly';
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
RETURN v_result;
|
RETURN v_result;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN OTHERS THEN
|
WHEN OTHERS THEN
|
||||||
RETURN 'ERROR_HANDLING: EXCEPTION - ' || SQLERRM;
|
RETURN 'ERROR_HANDLING: EXCEPTION - ' || SQLERRM;
|
||||||
END test_error_handling;
|
END test_error_handling;
|
||||||
|
|
||||||
PROCEDURE run_tests IS
|
PROCEDURE run_tests IS
|
||||||
v_test_result VARCHAR2(4000);
|
v_test_result VARCHAR2(4000);
|
||||||
BEGIN
|
BEGIN
|
||||||
DBMS_OUTPUT.PUT_LINE('=== PACK_JSON Test Suite ===');
|
DBMS_OUTPUT.PUT_LINE('=== PACK_JSON Test Suite ===');
|
||||||
DBMS_OUTPUT.PUT_LINE('');
|
DBMS_OUTPUT.PUT_LINE('');
|
||||||
|
|
||||||
-- Test 1: Basic parsing
|
-- Test 1: Basic parsing
|
||||||
v_test_result := test_basic_parsing();
|
v_test_result := test_basic_parsing();
|
||||||
DBMS_OUTPUT.PUT_LINE(v_test_result);
|
DBMS_OUTPUT.PUT_LINE(v_test_result);
|
||||||
|
|
||||||
-- Test 2: Array parsing
|
-- Test 2: Array parsing
|
||||||
v_test_result := test_array_parsing();
|
v_test_result := test_array_parsing();
|
||||||
DBMS_OUTPUT.PUT_LINE(v_test_result);
|
DBMS_OUTPUT.PUT_LINE(v_test_result);
|
||||||
|
|
||||||
-- Test 3: Nested objects
|
-- Test 3: Nested objects
|
||||||
v_test_result := test_nested_objects();
|
v_test_result := test_nested_objects();
|
||||||
DBMS_OUTPUT.PUT_LINE(v_test_result);
|
DBMS_OUTPUT.PUT_LINE(v_test_result);
|
||||||
|
|
||||||
-- Test 4: Error handling
|
-- Test 4: Error handling
|
||||||
v_test_result := test_error_handling();
|
v_test_result := test_error_handling();
|
||||||
DBMS_OUTPUT.PUT_LINE(v_test_result);
|
DBMS_OUTPUT.PUT_LINE(v_test_result);
|
||||||
|
|
||||||
DBMS_OUTPUT.PUT_LINE('');
|
DBMS_OUTPUT.PUT_LINE('');
|
||||||
DBMS_OUTPUT.PUT_LINE('=== Test Suite Complete ===');
|
DBMS_OUTPUT.PUT_LINE('=== Test Suite Complete ===');
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
@@ -568,8 +559,3 @@ FUNCTIONS:
|
|||||||
|
|
||||||
END PACK_JSON;
|
END PACK_JSON;
|
||||||
/
|
/
|
||||||
|
|
||||||
-- ====================================================================
|
|
||||||
-- Grant-uri pentru utilizarea package-ului
|
|
||||||
-- ====================================================================
|
|
||||||
-- GRANT EXECUTE ON PACK_JSON TO PUBLIC;
|
|
||||||
Reference in New Issue
Block a user