Skip to main content

Database Setup

The Sistema de Gestión de Propiedades API uses Cloudflare D1, a serverless SQLite database that runs on Cloudflare’s edge network.

What is D1?

Cloudflare D1 is a distributed SQLite database:
  • Serverless - No servers to manage
  • Global - Replicated to Cloudflare’s edge network
  • SQL - Full SQLite compatibility
  • Integrated - Native Workers integration

Database Schema

The database has a single propiedades table:
CREATE TABLE propiedades (
  codigo_id VARCHAR(6) PRIMARY KEY,
  pais VARCHAR(100),
  ciudad VARCHAR(100),
  direccion VARCHAR(255),
  ambientes INTEGER,
  metros_cuadrados DECIMAL(10,2),
  precio DECIMAL(15,2),
  tipo_contratacion TEXT CHECK(tipo_contratacion IN ('Alquiler', 'Venta')),
  estado TEXT CHECK(estado IN ('Disponible', 'Reservado', 'Alquilado', 'Vendido')),
  descripcion TEXT,
  fecha_publicacion DATE DEFAULT CURRENT_DATE
);
Source: Backend/schema.sql

Table Structure

ColumnTypeConstraintsDescription
codigo_idVARCHAR(6)PRIMARY KEYUnique property identifier
paisVARCHAR(100)Country
ciudadVARCHAR(100)City
direccionVARCHAR(255)Street address
ambientesINTEGERNumber of rooms
metros_cuadradosDECIMAL(10,2)Square meters
precioDECIMAL(15,2)Price
tipo_contratacionTEXTCHECK constraint”Alquiler” or “Venta”
estadoTEXTCHECK constraintProperty status
descripcionTEXTOptional description
fecha_publicacionDATEDEFAULT CURRENT_DATEPublication date

Constraints

  • PRIMARY KEY: codigo_id ensures each property has a unique identifier
  • CHECK constraints: Enforce valid enum values for tipo_contratacion and estado
  • DEFAULT: fecha_publicacion automatically set to current date

Creating the Database

1

Create D1 database

wrangler d1 create propiedades-db
Output:
✅ Successfully created DB 'propiedades-db'

[[d1_databases]]
binding = "DB"
database_name = "propiedades-db"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Copy the database_id for the next step.
2

Update wrangler.toml

Add the database configuration:
[[d1_databases]]
binding = "DB"
database_name = "propiedades-db"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
3

Run schema migration

wrangler d1 execute propiedades-db --file=./schema.sql
This creates the propiedades table.
4

Verify table creation

wrangler d1 execute propiedades-db --command="SELECT name FROM sqlite_master WHERE type='table'"
Should output: propiedades

Database Operations

Query the Database

# List all properties
wrangler d1 execute propiedades-db --command="SELECT * FROM propiedades"

# Count properties
wrangler d1 execute propiedades-db --command="SELECT COUNT(*) FROM propiedades"

# Get specific property
wrangler d1 execute propiedades-db --command="SELECT * FROM propiedades WHERE codigo_id='ZN1001'"

Insert Sample Data

Create a file sample-data.sql:
INSERT INTO propiedades (
  codigo_id, pais, ciudad, direccion, ambientes,
  metros_cuadrados, precio, tipo_contratacion, estado, descripcion
) VALUES (
  'ZN1001',
  'Argentina',
  'Tigre',
  'Av. Cazón 123',
  3,
  75.5,
  120000,
  'Venta',
  'Disponible',
  'Hermosa vista al río'
),
(
  'BA4567',
  'Argentina',
  'Buenos Aires',
  'Av. Corrientes 1234',
  2,
  65,
  95000,
  'Alquiler',
  'Disponible',
  'Departamento luminoso en el centro'
);
Execute it:
wrangler d1 execute propiedades-db --file=./sample-data.sql

Update Records

# Update property status
wrangler d1 execute propiedades-db --command="
  UPDATE propiedades 
  SET estado='Vendido' 
  WHERE codigo_id='ZN1001'
"

# Update price
wrangler d1 execute propiedades-db --command="
  UPDATE propiedades 
  SET precio=125000 
  WHERE codigo_id='ZN1001'
"

Delete Records

# Delete specific property
wrangler d1 execute propiedades-db --command="
  DELETE FROM propiedades 
  WHERE codigo_id='ZN1001'
"

# Clear all data (careful!)
wrangler d1 execute propiedades-db --command="DELETE FROM propiedades"

Local vs Production

Local Development Database

When running wrangler dev, a local SQLite database is used:
  • Located in .wrangler/state/v3/d1/
  • Independent from production
  • Persists between dev server restarts

Production Database

The production D1 database:
  • Globally distributed
  • Persistent across deployments
  • Accessed via Cloudflare’s network
Changes to the local dev database don’t affect production. Always run migrations in both environments.

Database Migrations

Running Migrations

wrangler d1 execute propiedades-db --local --file=./schema.sql

Migration Workflow

1

Create migration file

Create migrations/001_add_column.sql:
ALTER TABLE propiedades ADD COLUMN nueva_columna TEXT;
2

Test locally

wrangler d1 execute propiedades-db --local --file=./migrations/001_add_column.sql
3

Verify locally

wrangler dev
# Test the API
4

Apply to production

wrangler d1 execute propiedades-db --file=./migrations/001_add_column.sql

Backup and Restore

Export Database

# Export to SQL file
wrangler d1 execute propiedades-db --command=".dump" > backup.sql

# Export specific table
wrangler d1 execute propiedades-db --command=".dump propiedades" > propiedades-backup.sql

Import Database

wrangler d1 execute propiedades-db --file=./backup.sql

Database Inspection

View Schema

# Show table schema
wrangler d1 execute propiedades-db --command=".schema propiedades"

# List all tables
wrangler d1 execute propiedades-db --command="
  SELECT name FROM sqlite_master WHERE type='table'
"

Database Statistics

# Count records
wrangler d1 execute propiedades-db --command="
  SELECT COUNT(*) as total FROM propiedades
"

# Properties by status
wrangler d1 execute propiedades-db --command="
  SELECT estado, COUNT(*) as count 
  FROM propiedades 
  GROUP BY estado
"

# Properties by city
wrangler d1 execute propiedades-db --command="
  SELECT ciudad, COUNT(*) as count 
  FROM propiedades 
  GROUP BY ciudad
"

Programmatic Access

The API accesses D1 through the Workers binding:
// From Backend/src/controllers/propiedades.controller.ts

// List all properties
export const getAllPropiedades = async (c: Context) => {
  const { results } = await c.env.DB.prepare(
    'SELECT * FROM propiedades'
  ).all();
  return c.json(results);
};

// Get one property
export const getPropiedadById = async (c: Context) => {
  const id = c.req.param('id');
  const propiedad = await c.env.DB.prepare(
    'SELECT * FROM propiedades WHERE codigo_id = ?'
  ).bind(id).first();
  
  if (!propiedad) {
    return c.json({ error: 'Propiedad no encontrada' }, 404);
  }
  return c.json(propiedad);
};

// Insert property
await c.env.DB.prepare(`
  INSERT INTO propiedades (...) VALUES (...)
`).bind(...values).run();

// Update property
await c.env.DB.prepare(`
  UPDATE propiedades SET ... WHERE codigo_id = ?
`).bind(...values).run();

// Delete property
await c.env.DB.prepare(
  'DELETE FROM propiedades WHERE codigo_id = ?'
).bind(id).run();

Monitoring

View Database Metrics

In the Cloudflare Dashboard:
  1. Navigate to Workers & Pages
  2. Select D1
  3. Choose your database
View:
  • Query count
  • Storage size
  • Read/write operations

Query Logs

# Tail Worker logs to see database queries
wrangler tail

Limits

Cloudflare D1 limits (as of 2024):
ResourceFree PlanPaid Plan
Databases10Unlimited
Storage per DB500 MB10 GB
Reads per day5 millionUnlimited
Writes per day100,000Unlimited
See Cloudflare D1 Pricing for details.

Best Practices

1

Use prepared statements

Always use .bind() for user input to prevent SQL injection:
// Good
await db.prepare('SELECT * FROM propiedades WHERE codigo_id = ?')
  .bind(userInput).first();

// Bad - vulnerable to SQL injection
await db.prepare(`SELECT * FROM propiedades WHERE codigo_id = '${userInput}'`).first();
2

Test migrations locally

Always test schema changes with --local before applying to production.
3

Regular backups

Export your database regularly:
wrangler d1 execute propiedades-db --command=".dump" > backup-$(date +%Y%m%d).sql
4

Monitor query performance

Check slow queries in Wrangler logs and add indexes if needed.

Troubleshooting

Error: no such table: propiedadesSolution:
wrangler d1 execute propiedades-db --file=./schema.sql
Error: DB is not definedSolution: Check wrangler.toml has the D1 binding:
[[d1_databases]]
binding = "DB"
database_name = "propiedades-db"
database_id = "your-id"
Problem: Different data in dev vs productionSolution: Export production, import to local:
# Export from production
wrangler d1 execute propiedades-db --command=".dump" > prod-data.sql

# Import to local
wrangler d1 execute propiedades-db --local --file=./prod-data.sql

Next Steps

Environment Variables

Configure authentication credentials

Cloudflare Workers

Deploy the complete application

Property Schema

Detailed schema documentation

Creating Properties

Start adding properties to your database

Build docs developers (and LLMs) love