Un instrument de schele pentru proiecte care utilizeaza DataLoader, Flow si PostgreSQL.

  • Motivatie
    • Ce face acest lucru diferit de utilizarea unui ORM?
  • Comportament
    • Incarcator unic de chei
    • Incarcatoare _id unice
    • Incarcator de masa de unire non-unic
  • Conventiile de denumire
    • Introduceti numele
    • Numele proprietatilor
    • Numele incarcatorului
  • Exemple de utilizare
    • Generati incarcatoare DataLoader pentru toate tabelele bazei de date
    • Consumati codul generat
    • Gestionarea coloanelor care nu pot fi anulate in vizualizari materializate

Motivatie

Pastrarea bazei de date si a bazei de cod sincronizate este dificila. Ori de cate ori se fac modificari in schema bazei de date, aceste modificari trebuie reflectate in declaratiile de tip ale bazei de cod.

Majoritatea incarcatoarelor sunt necesare pentru a efectua cautari simple PK, de ex. UserByIdLoader. Scrierea acestei logici pentru fiecare tabel este o sarcina banala.

PostLoader rezolva aceste doua probleme prin:

  1. Crearea declaratiilor de tip pentru toate tabelele bazei de date.
  2. Crearea incarcatoarelor pentru cele mai comune cautari.

Daca sunteti interesat sa aflati mai multe, am scris un articol pe aceasta tema: am redus dimensiunea bazei de cod GraphQL cu 40% si am crescut acoperirea tipului la 90% +. Utilizarea generarii de cod pentru a crea incarcatoare de date pentru toate resursele bazei de date ..

Ce face acest lucru diferit de utilizarea unui ORM?

  1. ORM nu va va oferi tipuri stricte si completarea codului.
  2. ORM are cheltuieli de executie pentru construirea interogarilor si formatarea rezultatelor.

Comportament

PostLoader este un program CLI (si o colectie de utilitati) folosit pentru a genera cod pe baza unei scheme de baze de date PostgreSQL.

Codul generat consta din:

  1. Declaratii de tip flux care descriu fiecare tabel din baza de date.
  2. O functie din fabrica utilizata pentru a construi o colectie de incarcatoare.

Incarcator unic de chei

Se creeaza un incarcator pentru fiecare coloana dintr-un index unic (nu sunt acceptate indexuri unice, inclusiv mai multe coloane), de ex. UserByIdLoader.

Incarcator _id unic

Se creeaza un incarcator pentru fiecare coloana care are un nume care se termina cu _id.

Un incarcator non-unic este utilizat pentru a returna mai multe randuri pe cautare, de exemplu CitiesByCountryIdLoader. Datele de baza din acest exemplu provin dintr-un tabel numit „oras”. PostLoader foloseste modulul pluralize pentru a pluraliza numele tabelului.

Incarcator de masa de unire non-unic

Se creeaza un incarcator pentru fiecare resursa descoperibila printr-un tabel de alaturare.

  1. Un tabel de alaturare este format din cel putin 2 coloane care au nume care se termina _id.
  2. Numele tabelului este o concatenare a numelor coloanelor (fara sufix _id) (in ordine alfabetica, adica gen_film, nu gen_film).

Exemplu

Sa presupunem o relatie de mai multe la mai multe dintre filme si genuri:

CREATE TABLE film (ID intreg NU NULL, text nume); CREATE TABLE locul de desfasurare (ID intreg NOT NULL, text nume); CREATE TABLE genre_movie (id intreg NOT NULL, genre_id integer NOT NULL, movie_id integer NOT NULL);

Cu conditia schemei de mai sus, PostLoader va crea doua incarcatoare non-unice:

  • MoviesByGenreIdLoader
  • GenresByMovieIdLoader

Conventiile de denumire

Introduceti numele

Numele tipurilor sunt create din numele tabelelor.

Numele tabelului este imbracat in camila, prima litera este scrisa cu majuscule si este completata cu „RecordType”, de exemplu „film_rating” devine MovieRatingRecordType.

Numele proprietatilor

Numele de proprietati ale declaratiilor de tip sunt derivate din numele coloanelor tabelelor respective.

Numele coloanelor sunt acoperite cu camila, de exemplu „prenume” devine prenume.

Numele incarcatorului

Numele incarcatorului sunt create din numele tabelelor si numele coloanelor.

Numele tabelului este camel cased, prima litera este scrisa cu majuscule, sufixata cu constanta „By”, urmata de numele proprietatii (caramel caseed, prima litera este cu majuscule) folosita pentru a incarca resursa, urmata de constanta „Loader”, de ex. o inregistrare din tabelul „utilizator” cu coloana „id” poate fi incarcata utilizand incarcatorul UserByIdLoader.

Exemple de utilizare

Generati incarcatoare DataLoader pentru toate tabelele bazei de date

export POSTLOADER_DATABASE_CONNECTION_URI = postgres: // postgres: [email protected]/test export POSTLOADER_COLUMN_FILTER = “return / * exclude tabele care au o _view * /! columns.map (column => column.tableName). ‘) “export POSTLOADER_TABLE_NAME_MAPPER =” return tableName.endsWith (‘ _ view ‘)? tableName.slice (0, -5): tableName; ” export POSTLOADER_DATA_TYPE_MAP = “{\” email \ “: \” text \ “}” postloader generate-loaders> ./PostLoader.js

Aceasta genereaza un fisier care contine o functie din fabrica utilizata pentru a construi un DataLoader pentru fiecare tabel din baza de date si declaratiile de tip Flow in urmatorul format:

// @flow import {getByIds, getByIdsUsingJoiningTable} din „postloader”; import DataLoader din ‘dataloader’; tip de import {DatabaseConnectionType} din „slonik”; tip de export UserRecordType = {| + id: numar, + e-mail: sir, + dataNume: sir | nul, + FamilyName: sir | nul, + parola: sir, + creatAt: sir, + actualizat At: sir | nul, + pseudonim: sir |}; // [..] tip export LoadersType = {| + UserByIdLoader: DataLoader <numar, UserRecordType>, + UsersByAffiliateIdLoader: DataLoader <numar, $ ReadOnlyArray <UserRecordType>>, // [..] |}; // [..] export const createLoaders = (connection: DatabaseConnectionType) => {const UserByIdLoader = new DataLoader ((ids) => {return getByIds (connection, ‘user’, ids, ‘id’, ‘”id”, “e-mail”, “date_nume” ” }); const UsersByAffiliateIdLoader = new DataLoader ((ids) => {return getByIdsUsingJoiningTable (conexiune, ‘affiliate_user’, ‘user’, ‘user’, ‘affiliate’, ‘r2. “id”, r2.

pareja follando en la playa jovencitas peludas follando
enanas tetonas ancianas españolas follando
tetudas españolas porno gratis viejas
porno andaluz sexo playa nudista
sexo gratis incesto videos de maduras guarras
porno bix gitanas xxx
videos ponos porno forzadas
jovencitas españolas follando por dinero intercambio de parejas en español
mamadas gay halle berry desnuda
mama me folla potno
se folla a relatos sexo con maduros
tetonas cubanas porno andaluz
videdos porno madura se corre
incestos gays casadas cachondas
pilladas meando parejas liberales españolas
las mejores folladas maduras pajeando
follando real super mamadas
me hace una paja actores porno gay españoles
transexual española follando potro de bilbao
casadas follando por dinero seso gratis

“email”, r2. “given_name “” givenName “, r2.” family_name “” familyName “, r2.” password “, r2.” created_at “” createdAt “, r2.” updated_at “” updatedAt “, r2.” pseudonym “‘, ids);}) ; // [..] return {UserByIdLoader, UsersByAffiliateIdLoader, // [..]}; }; }); const UsersByAffiliateIdLoader = new DataLoader ((ids) => {return getByIdsUsingJoiningTable (connection, ‘affiliate_user’, ‘user’, ‘user’, ‘affiliate’, ‘r2. “id”, r2. “email”, r2. “given_name “” givenName “, r2.” family_name “” familyName “, r2.” password “, r2.” created_at “” createdAt “, r2.” updated_at “” updatedAt “, r2.” pseudonym “‘, ids);}) ; // [..] return {UserByIdLoader, UsersByAffiliateIdLoader, // [..]}; }; r2. “nume_familie” “numeFamilie”, r2. “parola”, r2. “creat_at” “creatAt”, r2. “actualizat_at” “actualizatAt”, r2. “pseudonim” ‘, id-uri); }); // [..] return {UserByIdLoader, UsersByAffiliateIdLoader, // [..]}; }; r2. “nume_familie” “numeFamilie”, r2. “parola”, r2. “creat_at” “creatAt”, r2. “actualizat_at” “actualizatAt”, r2. “pseudonim” ‘, id-uri); }); // [..] return {UserByIdLoader, UsersByAffiliateIdLoader, // [..]}; };

Observati ca fisierul generat depinde de pachetul postloader, adica trebuie sa instalati postloader ca dependenta principala de proiect (spre deosebire de o dependenta de dezvoltare).

Consumati codul generat

  1. Aruncati codul generat intr-un fisier din arborele proiectului dvs., de exemplu /generated/PostLoader.js.
  2. Creati o resursa de conectare PostgreSQL utilizand Slonik.
  3. Importati functia din fabrica createLoaders din fisierul generat.
  4. Creati colectiile de incarcatoare.
  5. Consumati incarcatoarele.

Exemplu:

// @flow import {createPool} din „slonik”; importati {createLoaders} din „./generated/PostLoader”; tip de import {UserRecordType} din ‘./generated/PostLoader’; const pool = createPool (‘postgres: //’); const loaders = createLoaders (pool); const user = await loaders.UserByIdLoader.load (1); const updateUserPassword = (utilizator: UserRecordType, newPassword: string) => {// [..]};

Optional, puteti trece un al doilea parametru la createLoaders – harta de configurare a incarcatorului, de ex

const loaders = createLoaders (conexiune, {UserByIdLoader: {cache: false}});

Gestionarea coloanelor care nu pot fi anulate in vizualizari materializate

Din pacate, PostgreSQL nu descrie coloanele de vizualizare materilizate ca fiind anulabile, chiar si atunci cand adaugati o constrangere care impune acest contract (consultati aceasta intrebare Stack Overflow).

Pentru vizualizarile materializate, trebuie sa identificati in mod explicit care coloane nu sunt anulabile. Acest lucru se poate face prin adaugarea de comentarii POSTLOAD_NOTNULL in coloana, de ex

COMENTAREAZA PE COLUMNA user.id ESTE „POSTLOAD_NOTNULL”; COMENTAREAZA PE COLUMN user.email ESTE „POSTLOAD_NOTNULL”; COMENTATIE PE COLUMNA user.password ESTE „POSTLOAD_NOTNULL”; COMENTAREAZA PE COLUMNA user.created_at ESTE „POSTLOAD_NOTNULL”; COMENTAREAZA PE COLUMNA user.pseudonym ESTE „POSTLOAD_NOTNULL”;

Alternativ, actualizati valoarea pg_attribute.attnotnull a coloanelor tinta, de ex

CREATI SAU INLOCUITI FUNCTIA set_attribute_not_null (view_name TEXT, column_names TEXT []) RETURNS void AS $$ BEGIN UPDATE pg_catalog.pg_attribute SET attnotnull = true WHERE attrelid IN (SELECT pa1.attrelid FROM pg_class pc1 INN. relnamespace INNER JOIN pg_attribute pa1 ON pa1.attrelid = pc1.oid AND pa1.attnum> 0 AND NOT pa1.attisdropped WHERE pn1.nspname = ‘public’ AND pc1.relkind = ‘m’ AND pc1.relname = view_name AND pa1.attname = ORICE (nume_coloana)); SFARSIT; $$ limba ‘plpgsql’; set_attribute_not_null (‘person_view’, ARRAY [‘id’, ‘imdb_id’, ‘tmdb_id’, ‘headshot_image_name’, ‘name’]);