Dominios en PostgreSQL
Dominios (Domains)
Los dominios en postgreSQL son un tipo de objeto, definido por el usuario, que permite abstraer la lógica de restricción de los campos en un único lugar, para simplificar su administración y mantenimiento.
Imaginen el tipo de dato “macaddr”, ¿qué hace este tipo de dato?, pues acepta una cadena que acepta única y exclusivamente el formato Mac Address (92:8c:a2:77:d1:8a), ¿y el tipo de dato inet?, pues acepta únicamente una cadena que sea igual a una dirección de red IP.
Entonces, ¿qué son exactamente los dominios?, nos permiten simplificar el diseño de nuestra base de datos, al centralizar las validaciones de un tipo de datos en un único lugar, con esto, en vez de tener decenas de campos “character varying, 65 de longitud, not-null con un constraint check ‘[\w.+_]+@[\w]+.[\w]{2,4}'”, lo que podemos decir es crear un dominio “email”, agregarle todas estas características y entonces todos nuestros campos serán de tipo “email”.
En este ejemplo, crearemos una función en PL/Python que valida códigos de barra de tipo EAN-13 y UPC (Universal Product Code), del típico código de barras en los productos de grandes almacenes y luego, crearemos un dominio llamado “barcode” que usará esta función en un constraint Check, de esta manera, podrán implementar una tabla de “inventario” con códigos de producto perfectamente válidos.
Comencemos!.
EAN y UPC
Universal Product Code (UPC) y European-International Article Number (EAN) son dos estándares internacionales creados para codificar, de manera universal, los productos de consumo masivo, sobre todo en anaqueles, para su perfecta categorización e inventario.
UPC fue el primer estándar, desarrollado en norteamérica y aún en uso, permite la codificación de productos usando un sencillo código de barras:
En 1977, una mejora sustancial de UPC, denominada European-Article-Numbering (EAN) fue implementada a través de una organización sin fines de lucro, con sede en Bruselas, Bélgica.
en 1990, la UCC (Uniform Code Council) de USA y la EAN firman un acuerdo para definir a EAN (ahora llamado International Article Number, pero mantiene el nombre EAN por costumbre) y para interoperar en un estándar global
en 2005, se renombra dicha organización mundial a partir de UCC y EAN, conocida como GS1 y es lanzada mundialmente.
¿Cómo funciona EAN?
Para quien cree que EAN es una simple tipografía de barritas anchas y flacas, está muy equivocado, EAN es un completo sistema de codificación de artículos universal, creado con un número conocido como Global Trade Item Number (GTIN), entonces, un EAN posee la siguiente “estructura”:
- Primeros 3 dígitos: representan el código GS1 del país, por ejemplo, el código GS1 de Venezuela es 759
- de 3 a 8 dígitos: representa toda la cadena de manufactura, el código de la compañia, y alternativamente su agencia, sub-bloque o cualquier otro código que identifique a la misma.
- de 2 a 6 dígitos: representa la referencia “interna” del producto (es decir, la coloca el fabricante, única por cada producto que “produzca”, valga a redundancia)
- Último dígito: es un dígito de chequeo, es un “checksum“, la idea de EAN es que sea fácilmente leíble por láser en todas las posiciones, incluidas diagonal, esto se logra leyendo rápidamente los números como los retorna el lector y aplicarle una función módulo 10, para determinar la correcta lectura del mismo.
El módulo de la división entera (entre 10) del total de operación de las 3 secciones, debe ser cero para ser un código válido.
Creando la función en PL/Python
Crear la función en PL/Python es asombrosamente sencillo, es tan básico como:
chars = str(codigo) total = 0 for i, c in enumerate(chars): total+= int(c) if i % 2 == 0 else int(c) * 3 return total % 10 == 0
Por ende, el bloque completo de la función PL/Python es:
CREATE OR REPLACE FUNCTION is_barcode(codigo bigint) RETURNS boolean AS $BODY$ chars = str(codigo) total = 0 for i, c in enumerate(chars): total+= int(c) if i % 2 == 0 else int(c) * 3 return total % 10 == 0 $BODY$ LANGUAGE plpythonu IMMUTABLE STRICT SECURITY DEFINER
Con lo cual, la primera parte ya está lista.
Creando el Dominio barcode
El dominio “barcode” será un tipo de datos BIGINT (para almacenar códigos EAN de 13 dígitos de longitud), que poseerá un constraint check basado en la función “is_barcode” diseñada anteriormente:
CREATE DOMAIN barcode AS bigint CONSTRAINT barcode_check CHECK (is_barcode(VALUE));
Y listo!, ya tenemos un tipo de datos llamado “barcode” que podemos usar en cualquier definición.
Probando Barcode
Vamos a crear una tabla de INVENTARIO muy sencilla:
CREATE TABLE inventario ( codigo barcode NOT NULL, producto character varying(60), CONSTRAINT pk_inventario PRIMARY KEY (barcode ) )
Dicha tabla, como ven tiene una PK llamada “codigo” de tipo “barcode” (puede naturalmente llamarse “barcode” pero lo llamé “codigo” para evitar confusión).
Vamos a insertar un par de datos:
Primero, algo válido:
insert into inventario VALUES(5127376511, ‘Omega 3 Fish Oil’)nota: un código UPC americano
insert into inventario VALUES(7591062013501, ‘Lafarcaína Oral Menta’)nota: un EAN-13 de un producto Venezolano (759 = Venezuela, 1062 = Laboratorios ELMOR)
Ya que EAN, UPC y JAN (Japanese Article Numbering) usan la misma función módulo 10, entonces la función valida cualquier factor de EAN-13, JAN-13, UPC-A y otros códigos de barra (como ISBN) que usen el mismo algoritmo, ejemplo:
insert into inventario VALUES(4534567890126, ‘Japanese Shampoo with JAN barcode’)Ahora, intentemos insertar algo erroneo:
insert into inventario VALUES(123456, ‘Test’)Esta inserción retornará:
ERROR: el valor para el dominio barcode viola la restricción check «barcode_check»
Y ahora algo que “creíamos” era un Barcode EAN-13 verdadero:
Lo cual obviamente retorna:
ERROR: el valor para el dominio barcode viola la restricción check «barcode_check»
Esto es debido a que:
- El código tiene un valor par (12) de longitud, lo que lo hace un UPC Americano (Universal product Code)
- Aunque el código de empresa está bien (709862) al no empezar en cero (0709862) falla el reconocimiento por ser un código de producto erróneo para el checksum digit asociado.
- Si el código de producto fuera 01201 y no 01301, el checksum sería 4, el código sería: 709862012014 y la función indicaría que es un código válido.
- Si fuera EAN, 709 sería un producto de Noruega!!!
¿Ven que nuestra función asociada a un Dominio trabaja de maravilla?
Espero le den utilidad a esta función, y ya saben:
Happy Hacking!
The post Crear un dominio en postgreSQL para validar códigos de barra appeared first on Phenobarbital con Soda.