@nextage/nx-frame-be
v1.0.60
Published
## GraphQL: la superficie generata
Readme
NxFrameBe Library
GraphQL: la superficie generata
generateSchema(ctrl, extension, mergeCodedEntity?, readOnly?) genera per ogni modulo quattro query
(count, list, get, findOne), nove mutation (create, update, remove, copy, le tre
mutation array, bulkUpdate, bulkRemove) e tre subscription. Le operazioni di dominio del modulo
si dichiarano a parte, in extension.typeDefs / extension.resolvers, e il generatore non le tocca.
Un modulo dichiara quali mutation generate non fanno parte della sua API con mutations:
schemaRegistry.register(ctrl, {
fields, typeDefs, resolvers, roles,
mutations: { create: false, copy: false, bulkUpdate: false, bulkRemove: false }
});- un'operazione a
falsenon e' generata: niente campo nello SDL, niente resolver; - assente o
true: generata come sempre - senza la mappa non cambia nulla; - una chiave che non nomina una mutation generata fa fallire la generazione;
- query, mutation custom e subscription non sono governate dalla mappa;
readOnly = truenon genera nessuna mutation e nessuna subscription, e prevale sulla mappa.
Rifiutare a runtime una mutation generata, con un resolver che lancia, resta possibile ma non e' il modo di togliere una superficie statica: l'operazione resterebbe pubblicata.
La LIST generata legge solo cio' che la selezione richiede (opt-in)
Un modulo con documenti pesanti puo' chiedere che la query LIST generata legga da Mongo solo i campi che il client ha selezionato:
schemaRegistry.register(ctrl, {
fields, typeDefs, resolvers, roles,
projection: { dependencies: { category: ['aclass'], label: ['name'] } }
});- i campi selezionati diventano una projection Mongo, con
_idsempre letto; conta il NOME del campo, non l'alias; inline fragment e fragment spread sono seguiti; di una selezione annidata si legge il path di primo livello (aclass { code }leggeaclass);__typenamee' ignorato; dependenciesdichiara, per campo GraphQL, i path che il suo field resolver legge oltre al campo stesso: per un campo calcolato, o per un resolver che legge altri campi del documento;- un campo selezionato che non e' un path dello schema e non e' dichiarato fa leggere il documento intero: un resolver di cui non si conoscono gli input non resta mai senza dati;
- vale SOLO per il resolver LIST generato:
count,get,findOne, le query custom e i chiamanti interni dictrl.listleggono documenti interi come prima; senzaprojectionnon cambia nulla.
Un ctrl.list sovrascritto riceve la projection nel parametro fields: e' li' che, per esempio, un
populate si puo' limitare ai campi selezionati.
Tenancy
Con un provider registrato su APP.tenancy, ogni modello il cui schema dichiara il campo del
proprietario e' scopato per default (tenancy: none per escluderlo). Tutte le operazioni generate lo
rispettano: letture per id e per filtro, create, update, remove e le loro varianti bulk, copy
(sorgente letta con lo scoping, proprietario della copia deciso dal provider) e le tre scritture array
(solo su un documento che il contesto puo' scrivere). Le primitive *Native non hanno hook ne'
scoping, per contratto.
Rimozione: la pipeline e' del framework, il predicato puo' essere del modello
BaseModel.remove(id, context) esegue beforeRemove, la delete, l'audit CRUD e afterRemove; nei
controller che pubblicano eventi la stessa chiamata sta nella transazione dell'outbox. Un modello che
deve vincolare la cancellazione a uno stato del documento non riscrive nulla di questo: sovrascrive
removeFilter(id, context) e restituisce le condizioni da aggiungere al filtro della delete.
- Le condizioni le giudica la delete stessa, in modo atomico: un documento che smette di soddisfarle
dopo
beforeRemove- una scrittura concorrente - resta. Un controllo inbeforeRemovesu uno stato che altri possono cambiare non lo garantirebbe. - Il filtro base si applica dopo le condizioni e non e' sovrascrivibile:
_ide, con la tenancy, il proprietario verificato - letto con la sessione del contesto, giudicato daassertWritablee pinnato nella delete, come nelle scritture array. Un documento il cui proprietario cambia fra la verifica e la delete non viene cancellato. Le condizioni possono quindi solo restringere. - Una delete che non cancella nulla - documento sparito o condizioni non soddisfatte - e' rifiutata con il
ForbiddenErrordi un documento mancante, senza audit e senzaafterRemove. Chi vuole dire al chiamante il motivo rilegge il documento dopo il rifiuto: quella lettura spiega l'esito, non lo cambia.
