Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions docs/DATABASE_SETUP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Setting up a database

## Docker Dev Environment

### Creating a database

Once your dev containers are running and you are inside the container, it is easy to create a development database.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am thinking about changing Once your dev containers to Once your dev container since the latter part of the sentence is talking about a single container?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think the statement is correct because we would have containers running for our chatbot_db and chatbot_server, so I would need to correct the statement to Once your dev containers are running and you are inside the chatbot_server container to show emphasis on where we will be creating tables in our db.
Thank you for pointing that out, Saumil.


First, install dependencies.

```bash
pnpm install
```

Then, create the database.

```bash
pnpm db:create
```

Finally, run the migrations to build the most current schema.

```bash
pnpm db:migrate
```

### Dropping a database

You can also delete the whole database, which is sometimes useful. Simply run

```bash
pnpm db:drop
```

**Note:** Any data that was saved will be lost and unrecoverable!
109 changes: 109 additions & 0 deletions docs/MIGRATIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Database Migrations

Our Chatbot db uses [Sequelize CLI](https://sequelize.org/docs/v6/other-topics/migrations/) to manage database migrations.

## Creating a Migration

To create a database migration skeleton, use the following command found in `package.json`.

``` bash
pnpm db:generate-migration --name <some_informative_name_about_your_model>
```

In `src/migrations`, you should now find a new migration file with an auto-generated timestamp.

Change the new migration's file extension to `.cjs`.

``` bash
202405121234-test.js ==> 202405121234-test.cjs
```

`*.js` files are set up to have a linting error if we use CommonJS style imports and exports, so `*.cjs` is used be explicit about the fact that we are using a different workflow from the rest of the project.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we change used be explicit to used to be explicit


## Adding Schema Changes

Below is the body of a sample migration to use as an example. Note that
the underlying Postgresql table should have **snake_cased** column names,
but that the table attributes should be **camelCase**. There is currently no way to appropriately set the table to handle auto-updating the `created_at` timestamp, but our models will take of it automatically.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about models will take of it automatically

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I need to correct that, thank you!


See the [Sequelize Docs](https://sequelize.org/) for more examples and info on adding indexes, etc.

``` javascript
'use strict';

module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('tests', {
id: {
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
primaryKey: true,
allowNull: false
},
name: {
type: Sequelize.STRING(100),
allowNull: false
},
description: {
type: Sequelize.TEXT,
allowNull: true
},
is_active: {
type: Sequelize.BOOLEAN,
defaultValue: true
},
difficulty_level: {
type: Sequelize.ENUM('easy', 'medium', 'hard'),
defaultValue: 'medium'
},
max_score: {
type: Sequelize.INTEGER
},
created_at: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
},
updated_at: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
},
deleted_at: {
type: Sequelize.DATE,
allowNull: true
}
});

},

down: async (queryInterface) => {
await queryInterface.dropTable('tests');
}
};
```

## Undoing a Migration

**These commands should be used very carefully!**
**Rolling back a migration may cause data loss!**

You can undo the most recent migration with

```bash
pnpm db:undo-migration
```

or undo the last n migrations with

```bash
pnpm db:rollback-migrations --to <first_migration_of_the_ones_to_rollback>
```

**Note:** The migration specified in the `--to` argument is included in the rollback!

Finally, undo every migration with

```bash
pnpm db:rollback-migrations
```
107 changes: 107 additions & 0 deletions docs/MODELS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Creating an ORM Model

Models are the way that we interact with our chatbot_server's underlying database.

First, create a new model in `src/models`.

```bash
touch src/models myModel.js(the name of your model) # Models should be camelCase

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest separating shell commands from inline comments:

touch src/models/myModel.js
(Models should be camelCase)

```

Second, create the model in the following format

```javascript
'use strict';
const { Model } = require('sequelize');

module.exports = (sequelize, DataTypes) => {
class Test extends Model {
static associate(models) {
// Define associations here (example)
// this.hasMany(models.TestResult, { foreignKey: 'test_id' });
}
}

Test.init({
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
allowNull: false
},
name: {
type: DataTypes.STRING(100),
allowNull: false,
validate: {
notEmpty: true,
len: [3, 100]
}
},
description: {
type: DataTypes.TEXT,
allowNull: true
},
is_active: {
type: DataTypes.BOOLEAN,
defaultValue: true
},
difficulty_level: {
type: DataTypes.ENUM('easy', 'medium', 'hard'),
defaultValue: 'medium'
},
max_score: {
type: DataTypes.INTEGER,
validate: {
min: 0,
max: 1000
}
}
}, {
sequelize,
modelName: 'Test',
tableName: 'tests',
timestamps: true,
underscored: true,
paranoid: true, // Enables soft deletes
});

return Test;
};
```



## Using the Model

You can go ahead and import the model in your service, and/or tests file as such and perform operations on the model given the demands of the tasks you're working on as such.

```javascript
// Import the model
const { Test } = require('./models');

// 1. Create a test
const newTest = await Test.create({
name: 'Math Assessment',
description: 'Basic algebra test',
difficulty_level: 'medium',
max_score: 100
});

// 2. Fetch tests
const tests = await Test.findAll({
where: { is_active: true },
limit: 10
});

// 3. Update a test
const [updatedRows] = await Test.update(
{ max_score: 150 },
{ where: { id: testId } }
);

// 4. Soft delete
await Test.destroy({ where: { id: testId } });

```

Once you restart the app, the Sequelize instance will be able to use the model.