From cc46cd9a5bb76d59991c16b9758da0f0923a9c9a Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Tue, 2 Apr 2019 19:26:48 +0200 Subject: [PATCH] GitHub Pages with jekyll --- docs/.gitignore | 3 + docs/404.html | 12 + docs/Gemfile | 23 ++ docs/Gemfile.lock | 254 +++++++++++++++++++ docs/_config.yml | 44 ++++ docs/_includes/content/getting_started.md | 76 ++++++ docs/_includes/nav.html | 44 ++++ docs/_layouts/default.html | 83 ++++++ docs/_layouts/feature.html | 8 + docs/docs/daos.md | 35 +++ docs/docs/getting_started.md | 11 + docs/docs/migrations.md | 43 ++++ docs/docs/transactions.md | 9 + docs/docs/writing_queries/custom_queries.md | 37 +++ docs/docs/writing_queries/writing_queries.md | 107 ++++++++ docs/index.md | 53 ++++ 16 files changed, 842 insertions(+) create mode 100644 docs/.gitignore create mode 100644 docs/404.html create mode 100644 docs/Gemfile create mode 100644 docs/Gemfile.lock create mode 100644 docs/_config.yml create mode 100644 docs/_includes/content/getting_started.md create mode 100644 docs/_includes/nav.html create mode 100644 docs/_layouts/default.html create mode 100644 docs/_layouts/feature.html create mode 100644 docs/docs/daos.md create mode 100644 docs/docs/getting_started.md create mode 100644 docs/docs/migrations.md create mode 100644 docs/docs/transactions.md create mode 100644 docs/docs/writing_queries/custom_queries.md create mode 100644 docs/docs/writing_queries/writing_queries.md create mode 100644 docs/index.md diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..45c15053 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,3 @@ +_site +.sass-cache +.jekyll-metadata diff --git a/docs/404.html b/docs/404.html new file mode 100644 index 00000000..d477dc46 --- /dev/null +++ b/docs/404.html @@ -0,0 +1,12 @@ +--- +layout: default +title: Page not found +permalink: /404 +nav_exclude: true +search_exclude: true +exclude: true +--- + +

Page not found

+ +

The page you requested could not be found. Try using the navigation {% if site.search_enabled %}or search {% endif %}to find what you're looking for or go to this site's home page.

\ No newline at end of file diff --git a/docs/Gemfile b/docs/Gemfile new file mode 100644 index 00000000..513e19e5 --- /dev/null +++ b/docs/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" + +# Hello! This is where you manage which Jekyll version is used to run. +# When you want to use a different version, change it below, save the +# file and run `bundle install`. Run Jekyll with `bundle exec`, like so: +# +# bundle exec jekyll serve +# +# This will help ensure the proper Jekyll version is running. +# Happy Jekylling! + +gem "just-the-docs" + +# If you want to use GitHub Pages, remove the "gem "jekyll"" above and +# uncomment the line below. To upgrade, run `bundle update github-pages`. +gem "github-pages", group: :jekyll_plugins + +# Windows does not include zoneinfo files, so bundle the tzinfo-data gem +gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby] + +# Performance-booster for watching directories on Windows +gem "wdm", "~> 0.1.0" if Gem.win_platform? + diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock new file mode 100644 index 00000000..8e14b1f8 --- /dev/null +++ b/docs/Gemfile.lock @@ -0,0 +1,254 @@ +GEM + remote: https://rubygems.org/ + specs: + activesupport (4.2.10) + i18n (~> 0.7) + minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) + tzinfo (~> 1.1) + addressable (2.5.2) + public_suffix (>= 2.0.2, < 4.0) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.11.1) + colorator (1.1.0) + commonmarker (0.17.13) + ruby-enum (~> 0.5) + concurrent-ruby (1.1.5) + dnsruby (1.61.2) + addressable (~> 2.5) + em-websocket (0.5.1) + eventmachine (>= 0.12.9) + http_parser.rb (~> 0.6.0) + ethon (0.12.0) + ffi (>= 1.3.0) + eventmachine (1.2.7) + execjs (2.7.0) + faraday (0.15.4) + multipart-post (>= 1.2, < 3) + ffi (1.10.0) + forwardable-extended (2.6.0) + gemoji (3.0.0) + github-pages (197) + activesupport (= 4.2.10) + github-pages-health-check (= 1.16.1) + jekyll (= 3.7.4) + jekyll-avatar (= 0.6.0) + jekyll-coffeescript (= 1.1.1) + jekyll-commonmark-ghpages (= 0.1.5) + jekyll-default-layout (= 0.1.4) + jekyll-feed (= 0.11.0) + jekyll-gist (= 1.5.0) + jekyll-github-metadata (= 2.12.1) + jekyll-mentions (= 1.4.1) + jekyll-optional-front-matter (= 0.3.0) + jekyll-paginate (= 1.1.0) + jekyll-readme-index (= 0.2.0) + jekyll-redirect-from (= 0.14.0) + jekyll-relative-links (= 0.6.0) + jekyll-remote-theme (= 0.3.1) + jekyll-sass-converter (= 1.5.2) + jekyll-seo-tag (= 2.5.0) + jekyll-sitemap (= 1.2.0) + jekyll-swiss (= 0.4.0) + jekyll-theme-architect (= 0.1.1) + jekyll-theme-cayman (= 0.1.1) + jekyll-theme-dinky (= 0.1.1) + jekyll-theme-hacker (= 0.1.1) + jekyll-theme-leap-day (= 0.1.1) + jekyll-theme-merlot (= 0.1.1) + jekyll-theme-midnight (= 0.1.1) + jekyll-theme-minimal (= 0.1.1) + jekyll-theme-modernist (= 0.1.1) + jekyll-theme-primer (= 0.5.3) + jekyll-theme-slate (= 0.1.1) + jekyll-theme-tactile (= 0.1.1) + jekyll-theme-time-machine (= 0.1.1) + jekyll-titles-from-headings (= 0.5.1) + jemoji (= 0.10.2) + kramdown (= 1.17.0) + liquid (= 4.0.0) + listen (= 3.1.5) + mercenary (~> 0.3) + minima (= 2.5.0) + nokogiri (>= 1.8.5, < 2.0) + rouge (= 2.2.1) + terminal-table (~> 1.4) + github-pages-health-check (1.16.1) + addressable (~> 2.3) + dnsruby (~> 1.60) + octokit (~> 4.0) + public_suffix (~> 3.0) + typhoeus (~> 1.3) + html-pipeline (2.10.0) + activesupport (>= 2) + nokogiri (>= 1.4) + http_parser.rb (0.6.0) + i18n (0.9.5) + concurrent-ruby (~> 1.0) + jekyll (3.7.4) + addressable (~> 2.4) + colorator (~> 1.0) + em-websocket (~> 0.5) + i18n (~> 0.7) + jekyll-sass-converter (~> 1.0) + jekyll-watch (~> 2.0) + kramdown (~> 1.14) + liquid (~> 4.0) + mercenary (~> 0.3.3) + pathutil (~> 0.9) + rouge (>= 1.7, < 4) + safe_yaml (~> 1.0) + jekyll-avatar (0.6.0) + jekyll (~> 3.0) + jekyll-coffeescript (1.1.1) + coffee-script (~> 2.2) + coffee-script-source (~> 1.11.1) + jekyll-commonmark (1.3.1) + commonmarker (~> 0.14) + jekyll (>= 3.7, < 5.0) + jekyll-commonmark-ghpages (0.1.5) + commonmarker (~> 0.17.6) + jekyll-commonmark (~> 1) + rouge (~> 2) + jekyll-default-layout (0.1.4) + jekyll (~> 3.0) + jekyll-feed (0.11.0) + jekyll (~> 3.3) + jekyll-gist (1.5.0) + octokit (~> 4.2) + jekyll-github-metadata (2.12.1) + jekyll (~> 3.4) + octokit (~> 4.0, != 4.4.0) + jekyll-mentions (1.4.1) + html-pipeline (~> 2.3) + jekyll (~> 3.0) + jekyll-optional-front-matter (0.3.0) + jekyll (~> 3.0) + jekyll-paginate (1.1.0) + jekyll-readme-index (0.2.0) + jekyll (~> 3.0) + jekyll-redirect-from (0.14.0) + jekyll (~> 3.3) + jekyll-relative-links (0.6.0) + jekyll (~> 3.3) + jekyll-remote-theme (0.3.1) + jekyll (~> 3.5) + rubyzip (>= 1.2.1, < 3.0) + jekyll-sass-converter (1.5.2) + sass (~> 3.4) + jekyll-seo-tag (2.5.0) + jekyll (~> 3.3) + jekyll-sitemap (1.2.0) + jekyll (~> 3.3) + jekyll-swiss (0.4.0) + jekyll-theme-architect (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-cayman (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-dinky (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-hacker (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-leap-day (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-merlot (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-midnight (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-minimal (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-modernist (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-primer (0.5.3) + jekyll (~> 3.5) + jekyll-github-metadata (~> 2.9) + jekyll-seo-tag (~> 2.0) + jekyll-theme-slate (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-tactile (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-time-machine (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-titles-from-headings (0.5.1) + jekyll (~> 3.3) + jekyll-watch (2.2.1) + listen (~> 3.0) + jemoji (0.10.2) + gemoji (~> 3.0) + html-pipeline (~> 2.2) + jekyll (~> 3.0) + just-the-docs (0.1.6) + jekyll (~> 3.3) + rake (~> 10.0) + kramdown (1.17.0) + liquid (4.0.0) + listen (3.1.5) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + ruby_dep (~> 1.2) + mercenary (0.3.6) + mini_portile2 (2.4.0) + minima (2.5.0) + jekyll (~> 3.5) + jekyll-feed (~> 0.9) + jekyll-seo-tag (~> 2.1) + minitest (5.11.3) + multipart-post (2.0.0) + nokogiri (1.10.2) + mini_portile2 (~> 2.4.0) + octokit (4.14.0) + sawyer (~> 0.8.0, >= 0.5.3) + pathutil (0.16.2) + forwardable-extended (~> 2.6) + public_suffix (3.0.3) + rake (10.5.0) + rb-fsevent (0.10.3) + rb-inotify (0.10.0) + ffi (~> 1.0) + rouge (2.2.1) + ruby-enum (0.7.2) + i18n + ruby_dep (1.5.0) + rubyzip (1.2.2) + safe_yaml (1.0.5) + sass (3.7.3) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + sawyer (0.8.1) + addressable (>= 2.3.5, < 2.6) + faraday (~> 0.8, < 1.0) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + thread_safe (0.3.6) + typhoeus (1.3.1) + ethon (>= 0.9.0) + tzinfo (1.2.5) + thread_safe (~> 0.1) + unicode-display_width (1.5.0) + +PLATFORMS + ruby + +DEPENDENCIES + github-pages + just-the-docs + tzinfo-data + +BUNDLED WITH + 2.0.1 diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 00000000..8649d572 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,44 @@ +# Welcome to Jekyll! +# +# This config file is meant for settings that affect your whole blog, values +# which you are expected to set up once and rarely edit after that. If you find +# yourself editing this file very often, consider using Jekyll's data files +# feature for the data you need to update frequently. +# +# For technical reasons, this file is *NOT* reloaded automatically when you use +# 'bundle exec jekyll serve'. If you change this file, please restart the server process. + +# Site settings +# These are used to personalize your new site. If you look in the HTML files, +# you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. +# You can create any custom variable you would like, and they will be accessible +# in the templates via {{ site.myvariable }}. +title: Moor +#email: your-email@example.com +description: >- # this means to ignore newlines until "baseurl:" + Moor is an easy to use, reactive, typesafe persistence library for Flutter apps. +baseurl: "/moor" # the subpath of your site, e.g. /blog +url: "https://simolus3.github.io" # the base hostname & protocol for your site, e.g. http://example.com +#twitter_username: jekyllrb +github_link: https://github.com/simolus3/moor + +search_enabled: true + + +# Build settings +markdown: kramdown +theme: just-the-docs +plugins: + - jekyll-feed + +# Exclude from processing. +# The following items will not be processed, by default. Create a custom list +# to override the default setting. +# exclude: +# - Gemfile +# - Gemfile.lock +# - node_modules +# - vendor/bundle/ +# - vendor/cache/ +# - vendor/gems/ +# - vendor/ruby/ diff --git a/docs/_includes/content/getting_started.md b/docs/_includes/content/getting_started.md new file mode 100644 index 00000000..a0eb68a2 --- /dev/null +++ b/docs/_includes/content/getting_started.md @@ -0,0 +1,76 @@ +### Adding the dependency +First, let's add moor to your project's `pubspec.yaml`. +At the moment, the current version of `moor_flutter` is [![Flutter version](https://img.shields.io/pub/v/moor_flutter.svg)](https://pub.dartlang.org/packages/moor_flutter) and the current version of `moor_generator` is [![Generator version](https://img.shields.io/pub/v/moor_generator.svg)](https://pub.dartlang.org/packages/moor_generator) + +```yaml +dependencies: + moor_flutter: # use the latest version + +dev_dependencies: + moor_generator: # use the latest version + build_runner: +``` +We're going to use the `moor_flutter` library to specify tables and access the database. The +`moor_generator` library will take care of generating the necessary code so the +library knows how your table structure looks like. + +### Declaring tables +Using moor, you can model the structure of your tables with simple dart code: +```dart +import 'package:moor_flutter/moor_flutter.dart'; + +// assuming that your file is called filename.dart. This will give an error at first, +// but it's needed for moor to know about the generated code +part 'filename.g.dart'; + +// this will generate a table called "todos" for us. The rows of that table will +// be represented by a class called "Todo". +class Todos extends Table { + IntColumn get id => integer().autoIncrement()(); + TextColumn get title => text().withLength(min: 6, max: 10)(); + TextColumn get content => text().named('body')(); + IntColumn get category => integer().nullable()(); +} + +// This will make moor generate a class called "Category" to represent a row in this table. +// By default, "Categorie" would have been used because it only strips away the trailing "s" +// in the table name. +@DataClassName("Category") +class Categories extends Table { + + IntColumn get id => integer().autoIncrement()(); + TextColumn get description => text()(); +} + +// this annotation tells moor to prepare a database class that uses both of the +// tables we just defined. We'll see how to use that database class in a moment. +@UseMoor(tables: [Todos, Categories]) +class MyDatabase { + +} +``` + +__⚠️ Note:__ The column definitions, the table name and the primary key must be known at +compile time. For column definitions and the primary key, the function must use the `=>` +operator and can't contain anything more than what's included in this `readme` and the +examples. Otherwise, the generator won't be able to know what's going on. + +### Generating the code +Moor integrates with the dart `build` system, so you can generate all the code needed with +`flutter packages pub run build_runner build`. If you want to continously rebuild the generated code +whever you change your code, run `flutter packages pub run build_runner watch` instead. +After running either command once, the moor generator will have created a class for your +database and data classes for your entities. To use it, change the `MyDatabase` class as +follows: +```dart +@UseMoor(tables: [Todos, Categories]) +class MyDatabase extends _$MyDatabase { + // we tell the database where to store the data with this constructor + MyDatabase() : super(FlutterQueryExecutor.inDatabaseFolder(path: 'db.sqlite')); + + // you should bump this number whenever you change or add a table definition. Migrations + // are covered later in this readme. + @override + int get schemaVersion => 1; +} +``` \ No newline at end of file diff --git a/docs/_includes/nav.html b/docs/_includes/nav.html new file mode 100644 index 00000000..2c4bf1ea --- /dev/null +++ b/docs/_includes/nav.html @@ -0,0 +1,44 @@ + diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html new file mode 100644 index 00000000..905d3f85 --- /dev/null +++ b/docs/_layouts/default.html @@ -0,0 +1,83 @@ + + + +{% include head.html %} + + +
+ +
+ +
+ {% unless page.url == "/" %} + {% if page.parent %} + + {% endif %} + {% endunless %} +
+ {{ content }} + + {% if page.has_children == true and page.has_toc != false %} +
+

Table of contents

+ {% assign children_list = site.pages | sort:"nav_order" %} +
    + {% for child in children_list %} + {% if child.parent == page.title and child.title != page.title %} +
  • + {{ child.title }} +
  • + {% endif %} + {% endfor %} +
+ {% endif %} + +
+ + Was this page helpful? Please + {% assign body= "From documentation site " %} + report an issue + if you have questions or problems. + +
+
+
+
+ + + diff --git a/docs/_layouts/feature.html b/docs/_layouts/feature.html new file mode 100644 index 00000000..e24f1c95 --- /dev/null +++ b/docs/_layouts/feature.html @@ -0,0 +1,8 @@ +--- +layout: default +--- +{% if page.since != nil %} +Available from {{page.since}} +{% endif %} + +{{ content }} \ No newline at end of file diff --git a/docs/docs/daos.md b/docs/docs/daos.md new file mode 100644 index 00000000..0ee05bd2 --- /dev/null +++ b/docs/docs/daos.md @@ -0,0 +1,35 @@ +--- +layout: post +title: Modularity with DAOs +nav_order: 5 +permalink: /daos/ +--- + +# Extracting functionality with DAOs +When you have a lot of queries, putting them all into one class quickly becomes +tedious. You can avoid this by extracting some queries into classes that are +available from your main database class. Consider the following code: +```dart +part 'todos_dao.g.dart'; + +// the _TodosDaoMixin will be created by moor. It contains all the necessary +// fields for the tables. The type annotation is the database class +// that should use this dao. +@UseDao(tables: [Todos]) +class TodosDao extends DatabaseAccessor with _TodosDaoMixin { + // this constructor is required so that the main database can create an instance + // of this object. + TodosDao(MyDatabase db) : super(db); + + Stream> todosInCategory(Category category) { + if (category == null) { + return (select(todos)..where((t) => isNull(t.category))).watch(); + } else { + return (select(todos)..where((t) => t.category.equals(category.id))) + .watch(); + } + } +} +``` +If we now change the annotation on the `MyDatabase` class to `@UseMoor(tables: [Todos, Categories], daos: [TodosDao])` +and re-run the code generation, a generated getter `todosDao` can be used to access the instance of that dao. \ No newline at end of file diff --git a/docs/docs/getting_started.md b/docs/docs/getting_started.md new file mode 100644 index 00000000..4a9ad3d1 --- /dev/null +++ b/docs/docs/getting_started.md @@ -0,0 +1,11 @@ +--- +layout: post +title: Getting started +nav_order: 1 +permalink: /getting-started/ +--- + +# Getting started +{% include content/getting_started.md %} + +Congrats, you are now ready to fully use moor and [write queries]({{site.url}}/writing-queries/). \ No newline at end of file diff --git a/docs/docs/migrations.md b/docs/docs/migrations.md new file mode 100644 index 00000000..a12a62f3 --- /dev/null +++ b/docs/docs/migrations.md @@ -0,0 +1,43 @@ +--- +layout: post +title: Migrations +nav_order: 4 +permalink: /migrations/ +--- +# Migrations +Moor provides a migration API that can be used to gradually apply schema changes after bumping +the `schemaVersion` getter inside the `Database` class. To use it, override the `migration` +getter. Here's an example: Let's say you wanted to add a due date to your todo entries: +```dart +class Todos extends Table { + IntColumn get id => integer().autoIncrement()(); + TextColumn get title => text().withLength(min: 6, max: 10)(); + TextColumn get content => text().named('body')(); + IntColumn get category => integer().nullable()(); + DateTimeColumn get dueDate => dateTime().nullable()(); // we just added this column +} +``` +We can now change the `database` class like this: +```dart + @override + int get schemaVersion => 2; // bump because the tables have changed + + @override + MigrationStrategy get migration => MigrationStrategy( + onCreate: (Migrator m) { + return m.createAllTables(); + }, + onUpgrade: (Migrator m, int from, int to) async { + if (from == 1) { + // we added the dueDate property in the change from version 1 + await m.addColumn(todos, todos.dueDate); + } + } + ); + + // rest of class can stay the same +``` +You can also add individual tables or drop them. You can't use the high-level query API in +migrations. If you need to use it, please specify the `onFinished` method on the +`MigrationStrategy`. It will be called after a migration happened and it's safe to call methods +on your database from inside that method. \ No newline at end of file diff --git a/docs/docs/transactions.md b/docs/docs/transactions.md new file mode 100644 index 00000000..61e40fb7 --- /dev/null +++ b/docs/docs/transactions.md @@ -0,0 +1,9 @@ +--- +layout: feature +title: Transactions +nav_order: 3 +since: 1.1 +--- + +# Transactions +TBD \ No newline at end of file diff --git a/docs/docs/writing_queries/custom_queries.md b/docs/docs/writing_queries/custom_queries.md new file mode 100644 index 00000000..c5e42534 --- /dev/null +++ b/docs/docs/writing_queries/custom_queries.md @@ -0,0 +1,37 @@ +--- +layout: post +title: Custom queries +parent: Writing queries +--- + +# Custom statements +You can also issue custom queries by calling `customUpdate` for update and deletes and +`customSelect` or `customSelectStream` for select statements. Using the todo example +above, here is a simple custom query that loads all categories and how many items are +in each category: +```dart +class CategoryWithCount { + final Category category; + final int count; // amount of entries in this category + + CategoryWithCount(this.category, this.count); +} + +// then, in the database class: +Stream> categoriesWithCount() { + // select all categories and load how many associated entries there are for + // each category + return customSelectStream( + 'SELECT *, (SELECT COUNT(*) FROM todos WHERE category = c.id) AS "amount" FROM categories c;', + readsFrom: {todos, categories}).map((rows) { + // when we have the result set, map each row to the data class + return rows + .map((row) => CategoryWithCount(Category.fromData(row.data, this), row.readInt('amount'))) + .toList(); + }); + } +``` +For custom selects, you should use the `readsFrom` parameter to specify from which tables the query is +reading. When using a `Stream`, moor will be able to know after which updates the stream should emit +items. If you're using a custom query for updates or deletes with `customUpdate`, you should also +use the `updates` parameter to let moor know which tables you're touching. diff --git a/docs/docs/writing_queries/writing_queries.md b/docs/docs/writing_queries/writing_queries.md new file mode 100644 index 00000000..04c09c32 --- /dev/null +++ b/docs/docs/writing_queries/writing_queries.md @@ -0,0 +1,107 @@ +--- +layout: post +title: Writing queries +nav_order: 2 +has_children: true +permalink: /writing-queries/ +--- + +__Note__: This assumes that you already have your database class ready. +Follow the [instructions][getting-started] over here on how to do that. + +# Writing queries +The examples here use the tables defined [here][getting-started]. +For each table you've specified in the `@UseMoor` annotation on your database class, +a corresponding getter for a table will be generated. That getter can be used to +run statements: +```dart +// inside the database class, the `todos` getter has been created by moor. + +// loads all todo entries +Future> get allTodoEntries => select(todos).get(); + +// watches all todo entries in a given category. The stream will automatically +// emit new items whenever the underlying data changes. +Stream> watchEntriesInCategory(Category c) { + return (select(todos)..where((t) => t.category.equals(c.id))).watch(); +} +``` +## Select statements +You can create `select` statements by starting them with `select(tableName)`, where the +table name +is a field generated for you by moor. Each table used in a database will have a matching field +to run queries against. Any query can be run once with `get()` or be turned into an auto-updating +stream using `watch()`. +### Where +You can apply filters to a query by calling `where()`. The where method takes a function that +should map the given table to an `Expression` of boolean. A common way to create such expression +is by using `equals` on expressions. Integer columns can also be compared with `isBiggerThan` +and `isSmallerThan`. You can compose expressions using `and(a, b), or(a, b)` and `not(a)`. +### Limit +You can limit the amount of results returned by calling `limit` on queries. The method accepts +the amount of rows to return and an optional offset. +### Ordering +You can use the `orderBy` method on the select statement. It expects a list of functions that extract the individual +ordering terms from the table. +```dart +Future> sortEntriesAlphabetically() { + return (select(todos)..orderBy([(t) => OrderingTerm(expression: t.title)])).get(); +} +``` +You can also reverse the order by setting the `mode` property of the `OrderingTerm` to +`OrderingMode.desc`. +## Updates and deletes +You can use the generated `row` class to update individual fields of any row: +```dart +Future moveImportantTasksIntoCategory(Category target) { + // use update(...).write when you have a custom where clause and want to update + // only the columns that you specify (here, only "category" will be updated, the + // title and description of the rows affected will be left unchanged). + // Notice that you can't set fields back to null with this method. + return (update(todos) + ..where((t) => t.title.like('%Important%')) + ).write(TodoEntry( + category: target.id + ), + ); +} + +Future update(TodoEntry entry) { + // using replace will update all fields from the entry that are not marked as a primary key. + // it will also make sure that only the entry with the same primary key will be updated. + // Here, this means that the row that has the same id as entry will be updated to reflect + // the entry's title, content and category. Unlike write, this supports setting columns back + // to null. As it set's its where clause automatically, it can not be used together with where. + return update(todos).replace(entry); +} + +Future feelingLazy() { + // delete the oldest nine entries + return (delete(todos)..where((t) => t.id.isSmallerThanValue(10))).go(); +} +``` +__⚠️ Caution:__ If you don't explicitly add a `where` clause on updates or deletes, +the statement will affect all rows in the table! + +## Inserts +You can very easily insert any valid object into tables: +```dart +// returns the generated id +Future addTodoEntry(Todo entry) { + return into(todos).insert(entry); +} +``` +All row classes generated will have a constructor that can be used to create objects: +```dart +addTodoEntry( + Todo( + title: 'Important task', + content: 'Refactor persistence code', + ), +); +``` +If a column is nullable or has a default value (this includes auto-increments), the field +can be omitted. All other fields must be set and non-null. The `insert` method will throw +otherwise. + +[getting-started]: {{ "/getting-started" | absolute_url }} \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..4cc1f66b --- /dev/null +++ b/docs/index.md @@ -0,0 +1,53 @@ +--- +layout: home +title: Home +nav_order: 0 +--- + +# Moor +{: .fs-9 } + +Moor is an easy to use, reactive persistence library for Flutter apps. Define your +database tables in pure Dart and enjoy a fluent query API, auto-updating streams +and more! +{: .fs-6 .fw-300 } + +[![Build Status](https://travis-ci.com/simolus3/moor.svg?token=u4VnFEE5xnWVvkE6QsqL&branch=master)](https://travis-ci.com/simolus3/moor) +[![codecov](https://codecov.io/gh/simolus3/moor/branch/master/graph/badge.svg)](https://codecov.io/gh/simolus3/moor) + +[Get started now]({{site.url}}/getting-started/){: .btn .btn-green .fs-5 .mb-4 .mb-md-0 .mr-2 } +[View on GitHub]({{site.github_link}}){: .btn .btn-outline .fs-5 .mb-4 .mb-md-0 .mr-2 } + +--- + +## Getting started +{% include content/getting_started.md %} + +You can ignore the `schemaVersion` at the moment, the important part is that you can +now run your queries with fluent Dart code: + +## TODO-List and current limitations +### Limitations (at the moment) +Please note that a workaround for most on this list exists with custom statements. + +- No `group by` or window functions + +### Planned for the future +These aren't sorted by priority. If you have more ideas or want some features happening soon, +let me know by creating an issue! +- Simple `COUNT(*)` operations (group operations will be much more complicated) +- Support Dart VM apps +- References + - DSL API + - Support in generator + - Validations +- Bulk inserts +- When inserts / updates fail due to invalid data, explain why that happened +### Interesting stuff that would be nice to have +Implementing this will very likely result in backwards-incompatible changes. + +- Find a way to hide implementation details from users while still making them + accessible for the generated code +- `GROUP BY` grouping functions +- Support for different database engines + - Support webapps via `AlaSQL` or a different engine