Full Transcript

TYPESCRIPT ========== **TypeScript** es un lenguaje de programación de código abierto **fuertemente tipado** que actúa como una extensión de JavaScript. En otras palabras, [es JavaScript con esteroides]. **¿Fuertemente tipado?** Pero, ¿Qué significa que sea un lenguaje \"fuertemente tipado\"? Rec...

TYPESCRIPT ========== **TypeScript** es un lenguaje de programación de código abierto **fuertemente tipado** que actúa como una extensión de JavaScript. En otras palabras, [es JavaScript con esteroides]. **¿Fuertemente tipado?** Pero, ¿Qué significa que sea un lenguaje \"fuertemente tipado\"? Recordemos que, dentro de las características básicas de JavaScript, se menciona que es un lenguaje de programación \"débilmente tipado\". Esto significa que las variables declaradas en JavaScript pueden cambiar de tipo de dato durante la ejecución de un programa. Por ejemplo, podríamos definir una variable x que sea inicializada con un valor numérico, y en algún otro lugar del código decidir cambiarla a un string. ![](media/image2.png)En TypeScript esto no sería posible ya que el tipo de dato es estático, lo que significa que está asociado a la variable en el momento de su creación y no permite que sea modificado nunca más, y el tratar de modificarlo conllevará a un error. **¿Por qué utilizar TypeScript?** En realidad, TypeScript nos da las mismas funcionalidades de JavaScript, pero con una capa extra de seguridad gracias a su sistema de tipado. Por esto se dice que son lenguajes "primos". Esto quiere decir que podemos trabajar código tal como lo haríamos con JavaScript, pero con la ventaja de que podemos supervisar la consistencia en los tipos de datos utilizados para prevenir comportamientos inesperados en el código o bugs. Consideremos el siguiente caso. Imagina que dentro de un archivo index.js típico existe una función que utiliza como argumento un string para imprimir algo en consola. Al trabajar con JavaScript estamos asumiendo que efectivamente ese argumento recibido será siempre un string. En el mejor escenario esto va a funcionar sin problemas, pero, ¿qué ocurre si en lugar de recibir un string la función recibe un número, un array o un objeto?: ![](media/image4.png) En efecto, obtenemos un error dado que el método toUpperCase solo está definido para strings. Este tipo de errores son más frecuentes de lo que creemos. **Ejemplo real** Cuando recibimos información de una API asumimos que la información vendrá de determinada manera, pero muchas veces viene con otro formato. Estos errores serían detectados únicamente al momento de ejecutar el código. TypeScript nos permite ahorrarnos estos errores. Este lenguaje hace una verificación en tiempo de compilación, ayudándonos a detectar errores **mientras escribimos el código** y [no al ejecutarlo]. Continuando con el ejemplo anterior, vamos a hacer una prueba de esto. Primero cambiaremos la extensión del archivo de index.js a index.**ts**. Luego vamos a agregarle a la variable user el tipado (user: string). Al hacer esto nos daremos cuenta que inmediatamente podemos ver los errores en la función sayHello() con los distintos argumentos. Además de brindarnos información sobre los errores de forma rápida, TypeScript incluye una herramienta nativa de autocompletado de funciones en el editor de texto, lo que lo vuelve más preciso dando opciones compatibles con el tipo de dato asociado. ![](media/image6.png) Es necesario hacer la observación de que los entornos de ejecución como node o los navegadores web **no tienen ni idea de qué es TypeScript** ni su sintaxis para tipar estáticamente, pues [solo trabajan con JavaScript]. Si intentamos ejecutar el archivo index.ts con node recibiremos errores. Para poder ejecutar este script es necesario que sea **previamente compilado (traducido) a JavaScript**. Para esto debemos realizar algunas configuraciones en nuestro programa. A continuación, exploraremos de qué se trata esto. **Configuración inicial de entorno** Para poder utilizar TypeScript es necesario instalarlo [dentro de nuestro proyecto o de forma global en nuestra computadora]. Esto lo podemos hacer con estos comandos. Con este comando podrás instalar TypeScript de forma global en tu computadora y utilizarlo sin problemas en cualquier proyecto. Este comando creará automáticamente un proyecto local de node con todas las dependencias de este lenguaje ya instaladas. ![](media/image8.png) NO instales TypeScript globalmente, ya que puede traer problemas de compatibilidad de versiones más adelante. Una vez hecho esto, podremos compilar el código TS a JS utilizando el comando **npx tsc index.ts**. Al hacerlo, nos daremos cuenta que dentro de nuestro proyecto se crea un archivo de.js. ¡Es un archivo de JavaScript básico! **ESLint** Antes de empezar con las bases de TypeScript vamos a aprender a cómo configurar un \"analizador de código\". Por analizador de código nos referimos a una herramienta que permite al lenguaje detectar e informar los errores conforme se escriben líneas de código. Si bien el análisis proporcionado nos permite trabajar en la mayoría de casos, hay ocasiones en las que las necesidades del proyecto requieren opciones más personalizables y de mayor alcance. Para ello, haremos uso de **ESLint**. ![](media/image10.png)ESLint es una herramienta para análisis de código de JavaScript, puede ser implementada con TypeScript mediante la adición de algunos [plugins] con características específicas. Para incorporarlo a nuestro proyecto, es necesario instalar dependencias que serán utilizadas durante el proceso de desarrollo, a través del comando... De esta forma podemos utilizar a ESLint para analizar y darle formato al código, aunque debemos hacer algunas configuraciones. En primera instancia, hay que crear un archivo de configuración llamado **.eslintrc.js** (nótese el punto del inicio) entro del cual configuraremos los plugins necesarios. Por último, solo tendrás que asignar en el package.json un nuevo script llamado **lint** con el valor de la imagen. ![](media/image12.png) **Tipos de datos básicos** Comenzaremos con los **tipos de datos primitivos** en TypeScript. El tipado para las variables que contienen estos datos, no necesariamente deben definirse de forma manual, puesto que este lenguaje puede [inferir el tipo] de forma automática. Este es un buen ejemplo de cuándo utilizar la asignación de tipos. En la práctica se hace una combinación de la asignación e inferencia de datos para generar código más legible y al mismo tiempo seguro. **En conclusión\...** En esta clase aprendimos un nuevo lenguaje: TypeScript. Vimos cuáles son las ventajas de hacer código utilizando el tipado estático y cómo configurar nuestro entorno de desarrollo para que nuestros proyectos puedan ser más seguros. Descubrimos que TypeScript provee una especie de \"asistente de desarrollo\" que está al tanto de nuestros posibles errores al momento de escribir código, compilando nuestros scripts con extensión.ts en archivos.js tradicionales. Finalmente, conocimos de qué manera hacer uso de los tipos de datos primitivos, así como a determinar en qué situaciones es beneficioso realizar el tipado estático manualmente y cuándo dejar que este sea inferido. TYPESCRIPT II ============= **Funciones y tipado** **¿Cómo tipar funciones?** ¿Recuerdas la clase anterior? Uno de los puntos que habíamos visto es la importancia de implementar **tipados estáticos** en nuestras variables. Esto nos permitía definir qué tipo de dato vamos a guardar en una variable. También exploramos el tipado en tipos de **datos primitivos** y de qué manera TypeScript nos proporciona una **inferencia** sobre estos. Ahora vamos a explorar cómo darles un [tipado a nuestras funciones], lo que permitirá conocer los posibles errores en el tiempo de compilación. ![](media/image14.png) Ahora que entendemos esto, ¿Qué sucede si los [parámetros] que le pasamos a una función poseen un tipo de dato más complejo? Como por ejemplo arrays u objetos. Para abordar este tema vamos a hablar sobre **interfaces**. **Interfaces y tipos personalizados** **¿Qué es una interfaz?** Las interfaces **permiten definir la forma que debe tener los tipos de datos más complejos.** En el caso de los objetos, por ejemplo, especifican qué propiedades deben contener, así como los tipos de datos asociados a sus valores. [No proporcionan una implementación real]. Es decir, solo establece las reglas que deben seguir. Como una especie de \"contrato\", para que el objeto sea compatible con la interfaz. **Veamos un ejemplo\...** Imagina que deseas construir algo con bloques y cada uno de estos es diferente a los demás. Algunos son cuadrados, otros rectangulares y otros circulares. También tienen propiedades como tamaño y color. Una interfaz sería una especie de plantilla que define cómo deben ser los bloques de cada tipo. Por ejemplo, la interfaz "Cuadrado" podría tener una propiedad "lado" de tipo número, mientras la interfaz "Rectángulo" tendría propiedades "ancho" y "largo" ambas de tipo número. ![](media/image16.png) Las interfaces ayudan a garantizar la consistencia y facilitan la comunicación entre diferentes partes del programa. Ahora sabemos utilizar parámetros según el tipo de dato: strings, numbers o booleanos, e incluso cómo construir aquellos más complejos, como los objetos, a partir de las interfaces. Pero, ya que conocemos las interfaces, vamos a trabajar ahora con una nueva herramienta similar: **tipos personalizados**. **Definición de tipos personalizados** Los tipos (types), similares a las interfaces, proporcionan reglas que nos permiten definir tipos de datos como objetos, arrays, funciones, etc. **Interfaces \| Casos de uso** Tanto las interfaces como los types permiten ser extendidos por otras interfaces o types. Esto quiere decir que pueden heredar información para usarla en sus propias estructuras. Sin embargo, lo más común es utilizar interfaces, debido a su legibilidad y mejor visualización de errores en compilación. Veamos un ejemplo haciendo uso de la palabra clave **extends**. En este caso, la interfaz [IEmpleado] podrá utilizar las propiedades de [ITrabajo] para definir sus propios objetos. Otra característica particular es que cuando creamos dos interfaces con el mismo nombre en distintas partes del código, ambas se comportan como una sola con toda la información. Aquí vemos que, a pesar que la interfaz se reescribió dos veces y con el mismo nombre, se comporta al final como una única con la información de ambas. ![](media/image18.png) **Tipos \| Casos de uso** Hay dos características muy comunes a las que se les da uso en types: **union** **types** y **alias**. Union types: Estos permiten describir valores que pueden ser uno de varios tipos posibles, ya sean primitivos o complejos. Por ejemplo, podemos definir un tipo con las tallas de camisas para una tienda virtual, con las opciones \"S\", \"M\", \"L\" y "XL", de manera que únicamente pueda tomar estos valores y valide, por ejemplo, si hay disponibles o no en stock. Para indicar que este será un nuevo tipo de dato debemos inicializarlo con el indicador type. Al utilizar unión types se proporciona una forma clara y segura de manejar casos en los que una variable puede tener distintos valores. Alias: Los alias de tipos son una característica en TypeScript que permiten asignar un nombre personalizado a un tipo existente o complejo. Esto facilita la creación de tipos reutilizables. En este caso, Coordenada [es un alias para un array de dos números]. Al utilizar este alias, estamos haciendo que el código sea más expresivo y fácil de entender. ![](media/image20.png) **En conclusión\...** En esta clase conocimos conceptos más avanzados, como el **tipado de funciones** en, **interfaces** y el **tipado** **personalizado**. Comprendimos cómo tipificar funciones, tanto sus parámetros como el valor que retornan, a partir de tipos de datos primitivos y complejos. Si nuestras funciones no retornan valores, TypeScript podrá inferirlo sin necesidad de escribirlo manualmente. Exploramos la creación y uso de **interfaces** y **tipos** para estructurar objetos. Vimos que, a pesar de que su comportamiento fuera similar, tenían casos de uso puntuales que los diferenciaba uno del otro, haciendo énfasis en la herencia, los unión types y los alias. EXPRESS & TYPESCRIPT ==================== **Breve repaso de herramientas** Antes de ver de qué manera ambas tecnologías se conectan para trabajar y desarrollar un proyecto más potente, recordemos un poco en qué consiste cada una de ellas. Express: Express es un framework minimalista para node, ideal para construir aplicaciones web y APIs. Su sencillez y flexibilidad lo convierten en una opción popular para el desarrollo backend con JavaScript o TypeScript. Hemos visto también que pueden agregarse middlewares y servicios, pero por ahora solo nos centraremos en lo básico de un servidor. Un ejemplo sencillo de cómo crear un servidor básico luce así. ![](media/image22.png) TypeScript: TypeScript es un lenguaje de programación que potencia las funcionalidades de JavaScript y que nos permite definir **tipados estáticos**, los cuales nos ayudarán a reducir comportamientos inesperados en la ejecución del código y que podemos prever en tiempo de compilación. Por ejemplo, al construir una función dejamos asignado explícitamente el tipo de datos que recibirá como argumentos y que retornará, en caso que devuelva algo: **¿Cómo se complementan?** La combinación de ambas tecnologías implica la creación de aplicaciones del lado servidor más mantenibles, escalables y eficientes. Podremos dar uso a los tipos estáticos de TS dentro de los controladores y las rutas para detectar posibles errores y prevenir comportamientos inesperados en nuestros proyectos. En este ejemplo vemos que la variable PORT recibe un valor string en lugar de uno numérico. Así que TSC nos notifica que es preciso realizar la corrección para poder levantar el servidor. ![](media/image24.png) En este otro ejemplo validamos la estructura de un nuevo usuario a partir de una interfaz Usuario, logrando ver errores en tiempo de compilación. En este caso, la propiedad extra no hace parte de la interfaz y de allí el error: Estos ejemplos nos muestran cómo TypeScript y Express trabajan juntos para darnos un desarrollo más completo y complementario. **Estructura de proyecto** **Inicialización de proyecto** Para avanzar, vamos a **construir una pequeña API Rest** para realizar solicitudes básicas de CRUD. Esto ya lo hemos realizado antes\... 1. Lo primero será crear un nuevo directorio con el comando [mkdir mi-proyecto] e ingresar al directorio del proyecto con [cd mi-proyecto]. 2. Una vez dentro, inicializamos el proyecto [utilizando npm init -y]. 3. Para instalar TypeScript, ingresa el comando [npm install \--save-dev typescript \@types/express \@types/node nodemon ts-node express]. **Archivos y carpetas** Comencemos añadiendo estratégicamente los diferentes archivos y directorios que usaremos en el proyecto, con el fin de trabajar de manera organizada. Los archivos de TS a compilar estarán ubicados en la **carpeta src** y el resultado de la compilación estará en una **carpeta dist** que se creará en su momento. El [target] señala que se compilará para la versión ES5 y se utilizará el sistema de **módulos CommonJS**. Con [strict] indicamos que se harán restricciones más rigurosas del código, lo que implica mayores comprobaciones por parte de TSC. Se incluirá en la compilación todos aquellos archivos dentro de src y sus directorios internos con extensión.ts y se omite la carpeta de node\_modules para la compilación. Solo nos resta configurar el script para ejecutar el proyecto. Como node no puede ejecutar código de TypeScript, **primero debe realizar la compilación**. Para esto, dentro del archivo package.json agregaremos un script build que ejecutará a TSC. Esto nos permitirá realizar la compilación al ejecutar el comando [npm run build]. En el script **start** agregamos [nodemon], pero esto sería muy poco práctico ya que cada vez que realicemos cambios en algún archivo de TS, deberíamos detener el servidor, ejecutar [npm run build] y volver a ejecutar [npm start]. Para evitar este proceso instalamos la dependencia **ts-node** con el comando que nos permite ejecutar archivos.ts directamente en node, sin necesidad de compilar previamente. Finalmente, usamos nodemon para reiniciar automáticamente nuestro servidor. Recuerda instalar también **dotenv** para la gestión de las variables de entorno (*npm install dotenv*). **Manejo de rutas** **Creación y tipado de rutas** ¿Recuerdas qué significa CRUD? Se refiere a las operaciones create, read, update y delete que podemos realizar en un servidor. Con todo lo que hemos aprendido hasta el momento sobre TypeScript, nuestro siguiente paso será construir rutas y controladores estáticamente tipadas. Lo primero que haremos será crear una interfaz llamada Recurso. Esta interfaz estará definida en un archivo llamado recursos.ts dentro de una nueva carpeta llamada routes en el directorio src. Esto nos permitirá realizar validaciones dentro de las rutas que haremos en su momento. ![](media/image26.png) Recuerda anteponer la letra I mayúscula en el nombre para resaltar el hecho de que es interfaz. En este mismo archivo, definiremos el **router** con cada uno de los métodos HTTP, por lo que deberemos importarlo junto con las interfaces **Request** y **Response** para manejar la solicitud y la respuesta a las peticiones, respectivamente. **Inserción de recursos** Lo primero que vamos a hacer es crear una ruta de tipo POST. Como sabemos, esta ruta va a recibir como primer valor un [endpoint] y como segundo una [función de callback (controlador)] que recibe como argumentos la [request] y [response]. Utilizaremos la interfaz de [IRecurso] para el tipado en la solicitud con [Request\], lo cual significa que esperamos recibir por body un objeto con esta estructura. **CRUD de recursos** Ya hemos creado nuestro primer recurso. Puedes seguir agregando todos los que desees. ¿Qué utilizaremos en los siguientes ejemplos? Lectura de Recursos: Para la lectura de recursos crearemos una ruta GET que ejecutará un controlador para obtener todos los recursos. Luego responderemos con la lista completa de estos. Actualización de recursos: Crearemos una ruta PUT para actualizar recursos existentes. En el controlador de la solicitud podremos asignar no sólo el tipo del recurso, sino también el valor recibido por params. Luego de esto, actualizamos y respondemos con el recurso actualizado. Si no existe, devolvemos un mensaje de error. Eliminación de recursos: En este ejemplo, añadiremos una ruta DELETE para eliminar recursos. En este caso, solo necesitamos validar el tipo de dato recibido por params, ya que no construiremos un nuevo recurso, por lo que la interfaz no será necesaria. Luego verificamos. Si el recurso existe, lo eliminamos y respondemos con el recurso eliminado. Si este no existe, devolvemos un mensaje de error. Este CRUD básico de express y TypeScript muestra cómo gestionar recursos de manera estructurada. La implementación de estas operaciones proporciona una base sólida para el desarrollo de aplicaciones más complejas. Veamos ahora, cómo podemos definir middlewares con este lenguaje. **Middlewares** **¿Qué era un middleware?** Los middlewares son funciones que juegan un papel importante en el manejo de solicitudes y respuestas en express. Estas [funciones "intermediarias"] realizan una tarea concreta antes de que la request llegue a su destino. Teniendo en cuenta esto, vamos a ver la creación de middlewares con TypeScript. **Tipado de middlewares** Vamos a crear una nueva carpeta llamada **middlewares** dentro de **src** en la cual agregaremos un archivo de nombre **autenticación.ts**. En este archivo vamos a definir un middleware para [verificar si un usuario tiene o no autorización] para acceder a cierto contenido de la API. La estructura base de un middleware es una función que recibe como argumentos a **request**, **response** y **next**, que nos permiten tomar la solicitud, analizarla y continuar al endpoint designado por la ruta. Para ello, importamos las interfaces [Request], [Response] y [NextFunction]. ![](media/image28.png) También vamos a enviar en esta función un **token** para saber que el usuario está autenticado y que tiene permiso para acceder a la información devuelta por el método GET. Esta información se envía a través de algo llamado \"**headers**\" de la petición. Un **header** es [información adicional] que acompaña a una solicitud y puede especificar, por ejemplo, el tipo de contenido que se envía (JSON, texto plano, etc.), la longitud del contenido y, en particular, datos de autenticación, como en nuestro caso. Recibiremos el token a través de una propiedad **headers** [del objeto request] y validaremos si este coincide con la palabra "autenticado". De ser así, la función next nos permitirá continuar con la petición. Caso contrario, se enviará un mensaje diciendo que no está autorizado. **En conclusión\...** En esta clase exploramos la sinergia entre TypeScript y express, como la ventaja de unir estas tecnologías hasta la creación de middlewares con tipado estático. Aprendimos cómo estructurar nuestros proyectos a partir de un esquema organizado de archivos y directorios. También vimos de qué manera configurar nuestro entorno de trabajo con node y TypeScript para generar adecuadamente un servidor y definir las posibles rutas. También aprovechamos el tipado estático para prevenir errores al momento de definir controladores y middlewares, cuyo comportamiento es el ya conocido en JavaScript. SQL FUNDAMENTALS ================ **Bases de datos relacionales** **Relacional** Hasta ahora sabemos que las [bases de datos] son **sistemas** que nos permiten gestionar la información de una aplicación de manera ordenada para manipular y registrar datos. Hemos trabajado hasta el día de hoy con **bases de datos no relacionales** (MongoDB), las cuales organizan la información en forma de **colecciones** y **documentos** (objetos) que pueden ser referenciados entre ellos mismos y poseen una estructura bastante flexible. Por otro lado, las **bases de datos relaciones** cumplen la misma función que las no relacionales, pero su principal diferencia es que la información se almacena en estructuras tabulares **(tablas)** compuestas por filas y columnas, en lugar de colecciones y documentos. Consideremos dos escenarios concretos para ilustrar mejor esta diferencia. El primero de ellos, será un **sistema de gestión** de pedidos en un comercio electrónico. En este tendremos tablas que representan usuarios, productos y pedidos. Podemos considerar que la tabla **Usuarios** guardará el mismo tipo de información para cada registro: nombre, email y contraseña. En la tabla Productos, cada uno de estos tendrá un nombre y un código de identificación. ![](media/image30.png) Finalmente, la tabla Pedidos va a contener el nombre del usuario, los productos adquiridos y la fecha de compra. Nuestro segundo escenario, será una **plataforma de redes sociales** en la que cada usuario tiene su propio perfil. Como podemos ver, las tablas en una **base de datos relacional** mantienen una [estructura estática] para la información que guardan en ellas. Cada usuario tiene las mismas características, así como los productos y pedidos. ![](media/image32.png) Los perfiles basados en una **base de datos no relacional**, no tienen esta condición. Por su parte, poseen un [esquema flexible] y pueden contener diferentes datos según las necesidades del proyecto. En el modelo relacional, una **entidad** se representa como una tabla que encapsula las características de un objeto, como el usuario del ejemplo anterior. ![](media/image34.png) Cada **columna** de la tabla representa los [atributos] o [propiedades] de esa entidad (por ejemplo, un identificador, nombre del usuario, email y teléfono) y las **filas** contienen los registros o instancias particulares de esa entidad (cada usuario individual). Cabe resaltar que una entidad puede ser cualquier concepto del mundo real, en el que necesites almacenar y gestionar datos. Para mantener esta integridad se especifica la **cardinalidad** entre tablas relacionadas. La cardinalidad nos indica [cuántos registros] de una tabla están asociados con cuántos de otra. Por ejemplo, si tenemos dos entidades, [Estudiantes] y [Cursos], estas podrían tener registros relacionados entre sí: Existen tres tipos posibles de cardinalidad dentro del modelo relacional: **Uno a Uno (1:1):** Cada fila en una tabla está relacionada a lo sumo con una fila en la otra tabla, y viceversa. En este caso, podemos definir, por ejemplo, que una entidad **Persona** se relacione con una entidad **Área** (nos referimos al \"área\" de una empresa), bajo la relación "dirigir". En palabras simples, diremos que "una persona dirige [una sola área] y, a su vez, un área es dirigido por [una sola persona]". ![](media/image36.png) **Uno a Muchos (1:N):** Cada fila en la tabla \"A\" puede estar relacionada con varias filas en la tabla \"B\", pero cada fila en la tabla \"B\" solo puede estar relacionada con una fila en la tabla \"A\". Continuando con las entidades del ejemplo anterior, diremos que, bajo la relación "trabajar", podemos considerar que "[muchas] personas trabajan en [una sola] área y, de la misma manera, en [una sola] área trabajan [muchas] personas". **Muchos a Muchos (N:M):** Varias filas en una tabla pueden estar relacionadas con varias filas en la otra tabla. Para este caso y considerando dos entidades, **Actor** y **Película**, bajo la relación "*actuar*", es pertinente decir que "cada actor puede actuar en [muchas] películas y, de forma análoga, en cada película actúan [muchos] actores". ![](media/image38.png) **¿Qué es SQL?** **SQL** (*Structured Query Language*) es un lenguaje estandarizado que permite realizar queries de información a una base de datos relacional. Estas queries pueden ser consultas, actualizaciones, inserciones o eliminación de datos. Es un [lenguaje declarativo], es decir, el usuario indica qué operación y qué resultado desea obtener y el sistema de gestión se encarga del procesamiento de la solicitud. Imagina que tienes una lista de mil usuarios y quieres felicitar a quienes cumplen años el día de hoy. No harás el proceso manualmente, ya que te llevaría mucho tiempo. Lo que harás es, mediante **comandos SQL**, señalar cuáles son las condiciones y la acción (en este caso, felicitara quienes cumplen años hoy). Ahora que entendemos la diferencia entre ambos paradigmas vamos a enfocarnos en trabajar con una base de datos relacional mediante **SQL**. Las bases de datos relacionales más utilizadas son estas: - PostgreSQL \-\-\--\> esta es la que utilizaremos. - MySQL - MariaDB - SQlite **PostgreSQL** **¿Qué es PostgreSQL?** **PostgreSQL** es una base de datos de código abierto y de alto rendimiento. Es hasta la fecha el sistema de gestión más utilizado en la industria. Podemos mencionar que cuenta con soporte completo para las consultas **SQL** e incorpora una amplia gama de tipos de datos propios y personalizados que facilitan la gestión de la información. Ahora que tienes tu **terminal shell** abierta (recuerda ingresar tus credenciales), te invitamos a crear una base de datos con el nombre **empleados**. **Importante** Todos los comandos que escribas dentro de esta terminal deben terminar en **punto y coma** (;) para que sean ejecutados correctamente. ![](media/image40.png)Para poder visualizar nuestras bases de datos dentro de PostgreSQL debemos ejecutar el comando **\\l** en la línea de comandos. Nos encontraremos un listado incluyendo la que acabamos de crear. Para conectarnos a empleados y trabajar sobre ella debemos utilizar el comando **\\c** especificando el nombre de la BD. Si la conexión se realiza con éxito verás el mensaje de la imagen. Es hora de empezar a llenar de información esta base de datos. **Veamos cómo construir las distintas tablas que la componen.** **Creación de tablas y constraints** **Create Table** El primer paso será crear las tablas correspondientes a las entidades que queremos definir dentro de nuestra base de datos. Para ello trabajaremos sobre el siguiente [modelo entidad relación] que representa la base de datos de los empleados de una empresa. ![](media/image42.png) Ya que estamos conectados a nuestra base de datos estamos listos para crear nuestras tablas. Utiliza el comando de la imagen, en el que las propiedades indican las características que tendrá cada columna de la tabla. Antes de ejecutar el comando anterior, conozcamos de qué manera podemos definir estas **propiedades**. **Constraints y tipos de datos** Las propiedades (columnas) de cada entidad deben tener asociado un **tipo de dato** que nos permite asegurar que la información de todas las instancias o registros de dicha tabla sea estandarizada, limitando la información que puede ser almacenada en ella. Algunos ejemplos de estos tipos de datos son: **character varying -- varchar(n):** Para strings que contengan entre 1 y n caracteres. **Integer -int:** Integers de 4 bytes, es decir, un número tan grande como 2 a la potencia 32. **Date:** Fechas de calendario con estructura año, mes, dia. Por defecto, cuando creamos una tabla siempre estará vacía. Veamos de qué manera podemos agregarles información y trabajar con ellas. **Estructura de una query** **Interacción con las tablas** Cuando hablamos de trabajar con tablas nos referimos a trabajar con información; añadirla, modificarla, eliminarla, etc. Para lograr este tipo de interacciones utilizaremos las **querys** que nos permite crear SQL. Hasta ahora hemos logrado **crear tablas** y realizar **solicitudes** operaciones de información. Todo esto dentro de tablas independientes. Pero, ¿Qué sucede si trabajamos con tablas que están relacionadas entre sí como el diagrama que habíamos visto anteriormente? **Relaciones en SQL** **Middlewares con express y ts** Como mencionamos anteriormente, es imprescindible planificar de antemano las relaciones que habrá entre nuestras tablas. Estas relaciones tendrán una **representación de la cardinalidad**. Tomemos nuestro diagrama, por ejemplo, junto a la tabla **EMPLEADOS** como base. Al crear esta tabla, tendremos que indicar las relaciones con el resto de las entidades. Debemos considerar que la tabla **departamentos** es la única que se relaciona con la tabla **localidades**, así que es necesario observar de qué manera lo hacen a partir de la [cardinalidad] vista al inicio de clase. ![](media/image42.png) **Join** Cuando realizamos solicitudes lo más común es que esa solicitud dependa de la información de dos o más tablas en función de la relación entre ellas. Para poder crear estas querys, **SQL** nos permite utilizar la cláusula llamada **JOIN** para unir la información entre tablas. Por ejemplo, si al realizar una solicitud en vez de visualizar las claves foráneas de cada tabla deseamos **conocer el valor** que representa, debemos [definir el punto de unión] entre ambas tablas. **Left Join:** Devuelve todas las filas de la tabla de la izquierda (A) y las filas correspondientes de la tabla de la derecha (B) cuando hay una coincidencia. Si no hay una coincidencia, devuelve **NULL** para las columnas de la tabla de la derecha. **Rigth Join:** Devuelve todas las filas de la tabla de la derecha (B) y las filas correspondientes de la tabla de la izquierda (A) cuando hay una coincidencia. Si no hay una coincidencia, devuelve **NULL** para las columnas de la tabla de la izquierda. **Full Outer Join:** Devuelve todas las filas cuando hay una coincidencia en una de las tablas. Si no hay una coincidencia, devuelve **NULL** para las columnas de la tabla sin coincidencias. **Inner Join:** Devuelve filas cuando hay una coincidencia en las tablas de ambos lados de la cláusula **JOIN**. Es decir, solo devuelve filas donde las columnas que participan en la condición de unión tienen valores que se encuentran en ambas tablas. Ya puedes operar de forma básica dentro de una base de datos relacional. Ahora demos el siguiente paso y hagamos solicitudes con mayor nivel de complejidad. **Filtrado y ordenamiento de datos** **Operadores de comparación** **SQL** integra también herramientas para [filtrar y comparar datos] de nuestras consultas a partir de operadores. Estos pueden ser utilizados para buscar registros con características muy particulares respecto a sus valores. Para crear las querys que nos permiten realizar estas solicitudes tenemos [múltiples herramientas] que nos ayudan a definir condiciones de filtro u ordenamiento. Una de ellas son los **operadores de comparación**. Estos operadores nos permiten utilizar cláusulas como **WHERE** o **JOIN** para comparar dos valores y devolver un resultado booleano que nos permitirá filtrar la información. Algunos de estos operadores son: Igual a (=) Diferente de (!=) Mayor que (\>) Menor que (\=) Menor o igual que (\

Use Quizgecko on...
Browser
Browser