doc: databases
This commit is contained in:
parent
154cbc9c32
commit
8556ae0b4c
|
@ -46,30 +46,82 @@ Let's create a fleck that makes a model so we can get a feel for how it works.
|
|||
|
||||
First, create a fleck in your application:
|
||||
|
||||
<Create pkg="tags" type="fleck" />
|
||||
<Create pkg="content" type="fleck" />
|
||||
|
||||
Now, let's hop into `packages/tags/src/index.js` and add a hook implementation:
|
||||
Now, let's hop into `packages/content/src/index.js` and add a hook implementation:
|
||||
|
||||
```javascript title="packages/tags/src/index.js"
|
||||
```javascript title="packages/content/src/index.js"
|
||||
export const hooks = {
|
||||
'@flecks/db/server.models': (flecks) => {
|
||||
const {Model, Types} = flecks.fleck('@flecks/db/server');
|
||||
class Tags extends Model {
|
||||
class Content extends Model {
|
||||
static get attributes() {
|
||||
return {
|
||||
key: {
|
||||
type: Types.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
value: {
|
||||
type: Types.STRING,
|
||||
text: {
|
||||
type: Types.TEXT,
|
||||
allowNull: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
return {
|
||||
Tags,
|
||||
Content,
|
||||
};
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Now, `npm start` your application and you will see that line looks different:
|
||||
|
||||
```
|
||||
@flecks/core/flecks gathered '@flecks/db/server.models': [ 'Content' ] +0ms
|
||||
```
|
||||
|
||||
Our model is recognized!
|
||||
|
||||
Let's add one more model and create an association between them:
|
||||
|
||||
```javascript title="packages/content/src/index.js"
|
||||
export const hooks = {
|
||||
'@flecks/db/server.models': (flecks) => {
|
||||
const {Model, Types} = flecks.fleck('@flecks/db/server');
|
||||
|
||||
class Content extends Model {
|
||||
|
||||
static get attributes() {
|
||||
return {
|
||||
text: {
|
||||
type: Types.TEXT,
|
||||
allowNull: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static associate({Tag}) {
|
||||
this.hasMany(Tag);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class Tag extends Model {
|
||||
|
||||
static get attributes() {
|
||||
return {
|
||||
value: {
|
||||
type: Types.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static associate({Content}) {
|
||||
this.belongsTo(Content);
|
||||
}
|
||||
|
||||
};
|
||||
return {
|
||||
Content,
|
||||
Tag,
|
||||
};
|
||||
},
|
||||
}
|
||||
|
@ -80,43 +132,48 @@ export const hooks = {
|
|||
`@flecks/db` uses [Sequelize](https://sequelize.org/) under the hood. You can dive into
|
||||
[their documentation](https://sequelize.org/docs/v6/getting-started/) to learn even more.
|
||||
|
||||
The static `attributes` method above is sugar on top of
|
||||
[`sequelize.define`](https://sequelize.org/docs/v6/core-concepts/model-basics/#using-sequelizedefine)
|
||||
and you should consult that documentation for more details on how to define and validate your
|
||||
models.
|
||||
|
||||
To implement associations between models, there is a static `associate` method. Suppose you also
|
||||
had a `Post` model along with your `Tags` model. You might do something like this in your `Tags`
|
||||
model:
|
||||
|
||||
```
|
||||
static associate({Post}) {
|
||||
Post.hasMany(this);
|
||||
this.hasMany(Post);
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
Now, `npm start` your application and you will see that line looks different:
|
||||
If you were to `npm start`, you would see the line:
|
||||
|
||||
```
|
||||
@flecks/core/flecks gathered '@flecks/db/server.models': [ 'Tags' ] +0ms
|
||||
@flecks/core/flecks gathered '@flecks/db/server.models': [ 'Content', 'Tag' ] +0ms
|
||||
```
|
||||
|
||||
Our model is recognized!
|
||||
|
||||
## Gathering models
|
||||
## Providing models with `Flecks.provide()`
|
||||
|
||||
When building Real:tm: applications we are usually going to need a bunch of models. If we add all
|
||||
of them into that one single file, things are going to start getting unwieldy. Let's create a
|
||||
`src/models` directory in our `packages/tags` fleck and add a `tags.js` source file with the
|
||||
following code:
|
||||
`src/models` directory in our `packages/content` fleck and add a `content.js` and `tag.js` source
|
||||
files with the following code:
|
||||
|
||||
```javascript title="packages/tags/src/models/tags.js"
|
||||
```javascript title="packages/content/src/models/content.js"
|
||||
export default (flecks) => {
|
||||
const {Model, Types} = flecks.fleck('@flecks/db/server');
|
||||
return class Tags extends Model {
|
||||
return class Content extends Model {
|
||||
|
||||
static get attributes() {
|
||||
return {
|
||||
text: {
|
||||
type: Types.TEXT,
|
||||
allowNull: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static associate({Tag}) {
|
||||
this.hasMany(Tag);
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
```javascript title="packages/content/src/models/tag.js"
|
||||
export default (flecks) => {
|
||||
const {Model, Types} = flecks.fleck('@flecks/db/server');
|
||||
return class Tag extends Model {
|
||||
|
||||
static get attributes() {
|
||||
return {
|
||||
key: {
|
||||
|
@ -129,16 +186,24 @@ export default (flecks) => {
|
|||
},
|
||||
};
|
||||
}
|
||||
|
||||
static associate({Content}) {
|
||||
this.hasMany(Content);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
};
|
||||
```
|
||||
|
||||
Notice that this looks very similar to how we defined the model above, but this time we're only
|
||||
returning the class.
|
||||
Notice that this looks very similar to how we defined the models above, but this time we're only
|
||||
returning the classes.
|
||||
|
||||
Now, hop over to `packages/tags/src/index.js` and let's rewrite the hook implementation:
|
||||
Now, hop over to `packages/content/src/index.js` and let's rewrite the hook implementation:
|
||||
|
||||
```javascript title="packages/content/src/index.js"
|
||||
import {Flecks} from '@flecks/core/server';
|
||||
|
||||
```javascript title="packages/tags/src/index.js"
|
||||
export const hooks = {
|
||||
'@flecks/db/server.models': Flecks.provide(require.context('./models')),
|
||||
}
|
||||
|
@ -146,65 +211,111 @@ export const hooks = {
|
|||
|
||||
We're passing the path to our models directory to `require.context` which is then passed to
|
||||
`Flecks.provide`. This is completely equivalent to our original code, but now we can add more
|
||||
models by adding individual files in `packages/tags/src/models` and keep things tidy.
|
||||
models by adding individual files in `packages/content/src/models` and keep things tidy.
|
||||
|
||||
:::info
|
||||
|
||||
For a more detailed treatment of gathering in flecks, see [the gathering guide](#todo).
|
||||
For a more detailed treatment of gathering and providing in flecks, see
|
||||
[the gathering guide](#todo).
|
||||
|
||||
:::
|
||||
|
||||
## Working with models
|
||||
|
||||
Let's do something with it. Edit `packages/tags/src/index.js` again like
|
||||
Let's do something with them. Edit `packages/content/src/index.js` again like
|
||||
so:
|
||||
|
||||
```javascript title="packages/tags/src/index.js"
|
||||
```javascript title="packages/content/src/index.js"
|
||||
import {Flecks} from '@flecks/core/server';
|
||||
|
||||
export const hooks = {
|
||||
// highlight-start
|
||||
'@flecks/server.up': async (flecks) => {
|
||||
const {Tags} = flecks.get('$flecks/db.models');
|
||||
console.log('There were', await Tags.count(), 'tags.');
|
||||
const {Content, Tag} = flecks.get('$flecks/db.models');
|
||||
console.log(
|
||||
'There were',
|
||||
await Content.count(), 'pieces of content',
|
||||
'and',
|
||||
await Tag.count(), 'tags.',
|
||||
);
|
||||
},
|
||||
// highlight-end
|
||||
'@flecks/db/server.models': Flecks.provide(require.context('./models')),
|
||||
}
|
||||
```
|
||||
|
||||
We have to configure `build/flecks.yml` so that the database comes up before we try to use it:
|
||||
|
||||
```yml
|
||||
'@db_test/content:./packages/content/src': {}
|
||||
'@flecks/core':
|
||||
id: db_test
|
||||
'@flecks/db': {}
|
||||
// highlight-start
|
||||
'@flecks/server':
|
||||
up:
|
||||
- '@flecks/db'
|
||||
- '@db_test/content'
|
||||
// highlight-end
|
||||
```
|
||||
|
||||
Now, another `npm start` will greet us with this line in the output:
|
||||
|
||||
```
|
||||
There were 0 tags.
|
||||
There were 0 pieces of content and 0 tags.
|
||||
```
|
||||
|
||||
Not very interesting. Let's add some, but only if there aren't any tags yet:
|
||||
Not very interesting. Let's add some, but only if there aren't any yet:
|
||||
|
||||
```javascript title="packages/tags/src/index.js"
|
||||
```javascript title="packages/content/src/index.js"
|
||||
export const hooks = {
|
||||
'@flecks/server.up': async (flecks) => {
|
||||
const {Tags} = flecks.get('$flecks/db.models');
|
||||
console.log('There were', await Tags.count(), 'tags.');
|
||||
const {Tag} = flecks.get('$flecks/db.models');
|
||||
console.log(
|
||||
'There were',
|
||||
await Content.count(), 'pieces of content',
|
||||
'and',
|
||||
await Tag.count(), 'tags.',
|
||||
);
|
||||
// highlight-start
|
||||
if (0 === await Tags.count()) {
|
||||
await Tags.create({key: 'foo', value: 'bar'});
|
||||
await Tags.create({key: 'another', value: 'thing'});
|
||||
if (0 === await Content.count()) {
|
||||
await Content.create(
|
||||
{text: 'lorem ipsum', Tags: [{value: 'cool'}, {value: 'trending'}]},
|
||||
{include: [Tag]}
|
||||
);
|
||||
await Content.create(
|
||||
{text: 'blah blah', Tags: [{value: 'awesome'}]},
|
||||
{include: [Tag]}
|
||||
);
|
||||
}
|
||||
console.log('There are', await Tags.count(), 'tags.');
|
||||
console.log(
|
||||
'There are',
|
||||
await Content.count(), 'pieces of content',
|
||||
'and',
|
||||
await Tag.count(), 'tags.',
|
||||
);
|
||||
// highlight-end
|
||||
},
|
||||
'@flecks/db/server.models': Flecks.provide(require.context('./models')),
|
||||
}
|
||||
```
|
||||
|
||||
Another `npm start` and we see the tags created!
|
||||
Another `npm start` and we see:
|
||||
|
||||
```
|
||||
There were 0 pieces of content and 0 tags.
|
||||
There are 2 pieces of content and 3 tags.
|
||||
```
|
||||
|
||||
Great!
|
||||
|
||||
## Persistence
|
||||
|
||||
You'll notice that if you run it again, it will always say
|
||||
|
||||
```
|
||||
There were 0 tags.
|
||||
There are 2 tags.
|
||||
There were 0 pieces of content and 0 tags.
|
||||
There are 2 pieces of content and 3 tags.
|
||||
```
|
||||
|
||||
What's up with that? Remember in the beginning:
|
||||
|
@ -212,12 +323,13 @@ What's up with that? Remember in the beginning:
|
|||
> By default, flecks will connect to an in-memory SQLite database to get you started instantly.
|
||||
|
||||
This means that the database will only persist as long as the life of your application. When you
|
||||
restart it, you'll get a fresh new database every time. Obviously, this isn't very helpful for
|
||||
any real purpose. Let's make a change to our `build/flecks.yml`:
|
||||
restart it, you'll get a fresh new database every time. It was **quick to get started** developing,
|
||||
but this isn't very helpful for any real purpose. Let's make a change to our `build/flecks.yml`:
|
||||
|
||||
```yml title="build/flecks.yml"
|
||||
'@db_test/tags:./packages/tags': {}
|
||||
'@flecks/core': {}
|
||||
'@db_test/content:./packages/content/src': {}
|
||||
'@flecks/core':
|
||||
id: db_test
|
||||
'@flecks/db': {}
|
||||
// highlight-start
|
||||
'@flecks/db/server':
|
||||
|
@ -229,16 +341,16 @@ any real purpose. Let's make a change to our `build/flecks.yml`:
|
|||
Now `npm start` again. You'll see our old familiar message:
|
||||
|
||||
```
|
||||
There were 0 tags.
|
||||
There are 2 tags.
|
||||
There were 0 pieces of content and 0 tags.
|
||||
There are 2 pieces of content and 3 tags.
|
||||
```
|
||||
|
||||
This time though, our application wrote the SQLite database to disk at `./persistent.sql`. If we
|
||||
give it one more go, we'll finally see what we expect:
|
||||
|
||||
```
|
||||
There were 2 tags.
|
||||
There are 2 tags.
|
||||
There were 2 pieces of content and 3 tags.
|
||||
There are 2 pieces of content and 3 tags.
|
||||
```
|
||||
|
||||
A persistent database!
|
||||
|
@ -277,8 +389,9 @@ Let's add another fleck to our project:
|
|||
Configure `build/flecks.yml`:
|
||||
|
||||
```yml title="build/flecks.yml"
|
||||
'@db_test/tags:./packages/tags': {}
|
||||
'@flecks/core': {}
|
||||
'@db_test/content:./packages/content/src': {}
|
||||
'@flecks/core':
|
||||
id: db_test
|
||||
'@flecks/db': {}
|
||||
// highlight-start
|
||||
'@flecks/db/server':
|
||||
|
@ -291,13 +404,13 @@ Configure `build/flecks.yml`:
|
|||
up:
|
||||
- '@flecks/docker'
|
||||
- '@flecks/db'
|
||||
- '@db_test/tags'
|
||||
- '@db_test/content'
|
||||
// highlight-end
|
||||
```
|
||||
|
||||
Notice that we configured `@flecks/server.up` to make sure to enforce a specific order in which
|
||||
our server flecks come up: first `@flecks/docker` to spin up the database, then
|
||||
`@flecks/db` to connect to the database, and finally our `@db_test/tags` fleck to interact with
|
||||
`@flecks/db` to connect to the database, and finally our `@db_test/content` fleck to interact with
|
||||
the database. This is important!
|
||||
|
||||
Now `npm start` will reveal the following message in the logs:
|
||||
|
|
Loading…
Reference in New Issue
Block a user