diff --git a/website/docs/database.mdx b/website/docs/database.mdx index 2b00848..18178ad 100644 --- a/website/docs/database.mdx +++ b/website/docs/database.mdx @@ -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: - + -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: