Skip to main content

Libreria Python Consultazione DB GAzie

Client Python per consultare (e aggiornare) il DB GAzie tramite php-crud-api.

Questa pagina è la guida d'uso completa.

Installazione

pip install py_gazie

Uso rapido

from py_gazie import GazieClient

with GazieClient("http://127.0.0.1:8082/modules/api/index.php", "test-token",
                 timeout=15, default_company="001") as client:

    product = client.get_table("product")       # alias -> ProductTable (gaz_001artico)
    resp = product.page(limit=5).search()       # chaining: prima i filtri/pagina, poi search()

    if resp.success:                            # controlla SEMPRE success
        for rec in resp.data.records:           # NavigableRecord: attributi, non .get()
            print(rec.codice, "-", rec.descri)
        print("totale:", resp.data.pagination.total_records)
    else:
        print("errore:", resp.status_code, resp.error)

Le tabelle: cosa passare a get_table()

Vuoi Passa Ricevi Sul wire
clienti "customer" CustomerTable gaz_{company}clfoco
articoli "product" ProductTable gaz_{company}artico
anagrafiche fiscali "anagra" AnagraTable gaz_anagra
aziende "company" CompanyTable gaz_aziend
documenti di fatturazione (testata) "document" DocumentTable gaz_{company}tesdoc
altre tabelle nome reale, es. "gaz_001catmer" GazieTable generica stesso nome
  • Solo gli alias attivano i metodi di dominio (insert_record, get_by_code, search_by_description, get_rows, get_customer…): il nome reale dà sempre la tabella generica.
  • Tabella inesistente (o company non presente sul server) → ValueError con il nome della tabella mancante.
  • Le tabelle sono cachate: stessa company+nome → stessa istanza. La company esplicita vince su default_company; entrambe sono normalizzate a 3 cifre (2'002').

Classe GazieTable — operazioni

Tutte le tabelle (alias e generiche) hanno lo stesso nucleo: create · update · delete · get_by_id · search · first · count · exists · add_filter · order_by. Schema del chaining:

t = client.get_table("customer")
t.and_filter("codice", "sw", "103")     # AND (ripeti per aggiungere)
t.or_filter("descri", "cs", "Fermi")    # OR (filter1/filter2)
t.add_filter("or", "descri,cs,Fermi")   # stessa cosa da stringa 'campo,op,valore'
t.page(1, 10).order_by("codice,desc")   # pagina + ordinamento (order_by = alias di order)
resp = t.search()                       # -> ApiResponse

resp = t.read()                         # lista | t.read(item_id) -> record singolo
resp = t.get_by_id(42)                  # UN record per chiave primaria -> ApiResponse
resp = t.first()                        # primo record o None
n    = t.count()                        # totale filtrato (misurato:14 su artico)
ok   = t.exists()                       # almeno uno?
resp = t.create({...}) / t.update(id, {...}) / t.delete(id)

⚠️ I filtri si accumulano sull'istanza e vengono azzerati solo quando leggi: mai lasciare filtri appesi senza chiamare search()/read().

Operatori di filtro (misurati sul server, 22/09/2026)

  • eq, neq, gt, sw (inizia per), cs (contiene), in (valori separati da ,)
  • lk viene ignorato dal server (restituisce tutto): usa cs
  • AND = filter ripetuto · OR = filter1/filter2 · misto = intersezione
  • niente virgole nei valori: il filtro è la stringa "campo,op,valore"

Formato della risposta

Ogni operazione ritorna un ApiResponse con quattro campi: success, status_code, data, error.

Cosa manda il server Come si legge in data
elenco {"records": [...], "results": N} PaginatedData: resp.data.records (lista), len(resp.data), resp.data.pagination.total_records
record singolo dict grezzo: resp.data["codice"]
errore (es. 404, code 1003) success=False, error="Record … not found"
warning PHP (colonna inesistente) ⚠️ success=True ma data è una stringa HTML: controlla il tipo

I record dei elenchi sono NavigableRecord: accesso per attributo (rec.codice, rec.indirizzo.citta per i campi annidati). Non esiste rec.get("codice").

resp = client.get_table("product").page(limit=5).search()
if resp.success and hasattr(resp.data, "records"):
    for rec in resp.data.records:
        print(rec.codice, rec.descri)

Cinque regole d'oro

  1. Controlla sempre resp.success — gli errori HTTP/rete diventano success=False, niente eccezioni.
  2. Record dagli elenchi → attributi (rec.campo), mai .get().
  3. I metodi dichiarati -> List[…] in realtà ritornano ApiResponse: leggi resp.data.records.
  4. Mai lk nei filtri (ignorato dal server): cs = contiene, eq = uguale.
  5. create() completa da solo il payload: legge lo schema create-{t} da /openapi e valorizza tutte le colonne tranne id (autoincrement, tornato come resp.data) — tu passi solo quelle che ti servono. Puoi passare datetime.date/datetime/Decimal: vengono convertiti in stringhe (formato server YYYY-MM-DD HH:MM:SS), perché json.dumps non accetta oggetti. company non è una colonna: non va nel payload.
  6. Su customer il codice lo calcola la libreria (progressivo mascli di gaz_aziend): create() e insert_record() ignorano il codice che passi e generano il prossimo del mastro (es. 103000009), riprovando se il server risponde 409 Duplicate key.

Adattare GAzie a CRUD PHP API

Per adattare il database GAzie a php-crud-api occorre inserire il campo id come chiave primaria ove non vi sia (php-crud-api lo richiede per gli URL /records/{tabella}/{id}).

Procedura da eseguire sul DB GAzie

DELIMITER //

DROP PROCEDURE IF EXISTS AddIdPrimaryKeyToGazie //

CREATE PROCEDURE AddIdPrimaryKeyToGazie()
BEGIN
    -- =========================================================================
    -- 1. TUTTE LE DICHIARAZIONI (Devono stare in cima)
    -- =========================================================================
    DECLARE done INT DEFAULT FALSE;
    DECLARE current_table VARCHAR(255);
    DECLARE old_pk_columns VARCHAR(512);
    
    -- Cursore per escludere tabelle con 'id' o con qualsiasi altro AUTO_INCREMENT
    DECLARE table_cursor CURSOR FOR 
        SELECT t.TABLE_NAME 
        FROM information_schema.TABLES t
        WHERE t.TABLE_SCHEMA = DATABASE()
          AND t.TABLE_NAME LIKE 'gaz_%'
          AND NOT EXISTS (
              SELECT 1 
              FROM information_schema.COLUMNS c 
              WHERE c.TABLE_SCHEMA = DATABASE() 
                AND c.TABLE_NAME = t.TABLE_NAME 
                AND c.COLUMN_NAME = 'id'
          )
          AND NOT EXISTS (
              SELECT 1 
              FROM information_schema.COLUMNS c 
              WHERE c.TABLE_SCHEMA = DATABASE() 
                AND c.TABLE_NAME = t.TABLE_NAME 
                AND c.EXTRA LIKE '%auto_increment%'
          );

    -- L'handler deve essere l'ultima cosa dichiarata
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;


    -- =========================================================================
    -- 2. ISTRUZIONI ESEGUIBILI
    -- =========================================================================
    
    -- Creazione della tabella temporanea per il LOG
    DROP TEMPORARY TABLE IF EXISTS temp_log_alter_tables;
    CREATE TEMPORARY TABLE temp_log_alter_tables (
        id INT AUTO_INCREMENT PRIMARY KEY,
        eseguito_alle TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        tabella_modificata VARCHAR(255),
        query_eseguita TEXT
    );

    OPEN table_cursor;

    read_loop: LOOP
        FETCH table_cursor INTO current_table;
        
        IF done THEN
            LEAVE read_loop;
        END IF;

        -- Recupera dinamicamente le colonne che compongono l'attuale chiave primaria
        SELECT GROUP_CONCAT(COLUMN_NAME SEPARATOR ', ')
        INTO old_pk_columns
        FROM information_schema.KEY_COLUMN_USAGE
        WHERE TABLE_SCHEMA = DATABASE()
          AND TABLE_NAME = current_table
          AND CONSTRAINT_NAME = 'PRIMARY';

        -- Se esiste una vecchia chiave primaria, procediamo
        IF old_pk_columns IS NOT NULL THEN
            
            SET @dynamic_sql = CONCAT(
                'ALTER TABLE `', current_table, '` ',
                'DROP PRIMARY KEY, ',
                'ADD COLUMN `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST, ',
                'ADD UNIQUE KEY `uk_', current_table, '_old_pk` (', old_pk_columns, ');'
            );

            -- Scrittura nel LOG
            INSERT INTO temp_log_alter_tables (tabella_modificata, query_eseguita) 
            VALUES (current_table, @dynamic_sql);

            -- Esecuzione della query
            PREPARE stmt FROM @dynamic_sql;
            EXECUTE stmt;
            DEALLOCATE PREPARE stmt;
            
        END IF;

    END LOOP;

    CLOSE table_cursor;
    
    -- 3. Stampa a schermo del risultato finale
    SELECT * FROM temp_log_alter_tables;
    
    -- Pulizia finale
    DROP TEMPORARY TABLE IF EXISTS temp_log_alter_tables;

END //

DELIMITER ;

Chiamare la procedura

CALL AddIdPrimaryKeyToGazie();

Release files for py-gazie 0.1.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for py-gazie 0.1.7
File Size Uploaded
py_gazie-0.1.7.tar.gz 87.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for py-gazie 0.1.7
File Interpreter ABI Platform
py_gazie-0.1.7-py3-none-any.whl Python 3 none any Details

Total release size: 216.7 kB

Release files / py_gazie-0.1.7.tar.gz

Download URL py_gazie-0.1.7.tar.gz
Size 87.2 kB
Tags Source
SHA-256 checksum
How to use checksums
095ff8bd46fc1cd92ebf135eb83c95c9d3b1e4d3fa57c6ba0298681b3068e4ae
BLAKE2b-256 checksum
How to use checksums
a320904c4e64957e6234c0dace5314ea812c23040026ef24009f44bf754852d1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / py_gazie-0.1.7-py3-none-any.whl

Download URL py_gazie-0.1.7-py3-none-any.whl
Size 129.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2a12026539372dfcfb03901f4efad8059f54518351617ecdb3865e0fda728eec
BLAKE2b-256 checksum
How to use checksums
f94cc7174ce1293a232880f804ddb1755dc7f117453bd68f0619571cb2eb0b9c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

0.1.7 This release

2 release files

0.1.6

2 release files

0.1.5

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page