Permalink
Browse files

Merge pull request #265 from vinicius73/patch-1

add highlight code
  • Loading branch information...
2 parents 0e7f93d + 41bcb80 commit a6724967b82f9b3ee60742f682c76a231cad26dd @danikp danikp committed on GitHub Apr 15, 2017
Showing with 136 additions and 101 deletions.
  1. +136 −101 README.md
View
237 README.md
@@ -28,55 +28,56 @@ Write an adapter: https://github.com/ChicagoBoss/ChicagoBoss/wiki/DB-Adapter-Qui
Usage
-----
-
- boss_db:start(DBOptions),
- boss_cache:start(CacheOptions), % If you want cacheing with Memcached
- boss_news:start() % Mandatory! Hopefully will be optional one day
-
- DBOptions = [
- {adapter, mock | tyrant | riak | mysql | pgsql | mnesia | mongodb},
- {db_host, HostName::string()},
- {db_port, PortNumber::integer()},
- {db_username, UserName::string()},
- {db_password, Password::string()},
- {db_database, Database::string()},
- {db_configure, DatabaseOptions::list()},
- {db_ssl, UseSSL::boolean() | required}, % for now pgsql only
-
- {shards, [
- {db_shard_models, [ModelName::atom()]},
- {db_shard_id, ShardId::atom()},
- {db_host, _}, {db_port, _}, ...
- ]},
- {cache_enable, true | false},
- {cache_exp_time, TTLSeconds::integer()}
- ]
-
- CacheOptions = [
- {adapter, memcached_bin | redis | ets},
- {cache_servers, MemcachedCacheServerOpts | RedisCacheServerOpts | EtsCacheServerOpts}
- ]
-
- MemcachedCacheServerOpts = [
- { HostName::string() = "localhost"
- , Port::integer() = 11211
- , Weight::integer() = 1
- }, ...
- ]
-
- RedisCacheServerOpts = [
- {host, HostName::string() = "localhost"},
- {port, Port::integer() = 6379},
- {pass, Password::string() = undefined},
- {db, Db::integer() = 0},
- {reconnect, Reconnect::boolean() = true}
- ]
-
- EtsCacheServerOpts = [
- {ets_maxsize, MaxSize::integer() = 32 * 1024 * 1024},
- {ets_threshold, Threshold::float() = 0.85},
- {ets_weight, Weight::integer() = 30}
- ]
+```erlang
+boss_db:start(DBOptions),
+boss_cache:start(CacheOptions), % If you want cacheing with Memcached
+boss_news:start() % Mandatory! Hopefully will be optional one day
+
+DBOptions = [
+ {adapter, mock | tyrant | riak | mysql | pgsql | mnesia | mongodb},
+ {db_host, HostName::string()},
+ {db_port, PortNumber::integer()},
+ {db_username, UserName::string()},
+ {db_password, Password::string()},
+ {db_database, Database::string()},
+ {db_configure, DatabaseOptions::list()},
+ {db_ssl, UseSSL::boolean() | required}, % for now pgsql only
+
+ {shards, [
+ {db_shard_models, [ModelName::atom()]},
+ {db_shard_id, ShardId::atom()},
+ {db_host, _}, {db_port, _}, ...
+ ]},
+ {cache_enable, true | false},
+ {cache_exp_time, TTLSeconds::integer()}
+]
+
+CacheOptions = [
+ {adapter, memcached_bin | redis | ets},
+ {cache_servers, MemcachedCacheServerOpts | RedisCacheServerOpts | EtsCacheServerOpts}
+]
+
+MemcachedCacheServerOpts = [
+ { HostName::string() = "localhost"
+ , Port::integer() = 11211
+ , Weight::integer() = 1
+ }, ...
+]
+
+RedisCacheServerOpts = [
+ {host, HostName::string() = "localhost"},
+ {port, Port::integer() = 6379},
+ {pass, Password::string() = undefined},
+ {db, Db::integer() = 0},
+ {reconnect, Reconnect::boolean() = true}
+]
+
+EtsCacheServerOpts = [
+ {ets_maxsize, MaxSize::integer() = 32 * 1024 * 1024},
+ {ets_threshold, Threshold::float() = 0.85},
+ {ets_weight, Weight::integer() = 30}
+]
+```
Introduction
------------
@@ -87,30 +88,38 @@ named fields without resorting to verbosities like proplists:get_value/2 or
dict:find/2. For example, if you want to look up a puppy by ID and print its
name, you would write:
- Puppy = boss_db:find("puppy-1"),
- io:format("Puppy's name: ~p~n", [Puppy:name()]).
+```erlang
+Puppy = boss_db:find("puppy-1"),
+io:format("Puppy's name: ~p~n", [Puppy:name()]).
+```
Functions for accessing field names are generated automatically. All you need
to do is create a model file and compile it with boss_record_compiler. Example:
The model file, call it puppy.erl:
- -module(puppy, [Id, Name, BreedId]).
+```erlang
+-module(puppy, [Id, Name, BreedId]).
+```
Then compile it like:
- {ok, puppy} = boss_record_compiler:compile("puppy.erl")
+```erlang
+{ok, puppy} = boss_record_compiler:compile("puppy.erl")
+```
...and you're ready to go.
You can also enable boss_db_rebar plugin in your rebar.config to automatize
compilation:
- {plugin_dir, ["deps/boss_db/priv/rebar"]}.
- {plugins, [boss_db_rebar]}.
- {boss_db_opts, [
- {model_dir, "src/model"}
- ]}.
+```erlang
+{plugin_dir, ["deps/boss_db/priv/rebar"]}.
+{plugins, [boss_db_rebar]}.
+{boss_db_opts, [
+ {model_dir, "src/model"}
+]}.
+```
Associations
------------
@@ -119,38 +128,49 @@ BossDB supports database associations. Suppose you want to model the dog breed
(golden retriever, poodle, etc). You would create a model file with a special
"-has" attribute, like:
- -module(breed, [Id, Name]).
- -has({puppies, many}).
-
+```erlang
+-module(breed, [Id, Name]).
+-has({puppies, many}).
+```
Then back in puppy.erl you'd add a "-belongs_to" attribute:
- -module(puppy, [Id, Name, BreedId]).
- -belongs_to(breed).
+```erlang
+-module(puppy, [Id, Name, BreedId]).
+-belongs_to(breed).
+```
Once you've compiled breed.erl with boss_record_compiler, you can print a puppy's
associated breed like:
- Breed = Puppy:breed(),
- io:format("Puppy's breed: ~p~n", [Breed:name()]).
+```erlang
+Breed = Puppy:breed(),
+io:format("Puppy's breed: ~p~n", [Breed:name()]).
+```
Similarly, you could iterate over all the puppies of a particular breed:
- Breed = boss_db:find("breed-47"),
- lists:map(fun(Puppy) ->
- io:format("Puppy: ~p~n", [Puppy:name()])
- end, Breed:puppies())
+```erlang
+Breed = boss_db:find("breed-47"),
+lists:map(fun(Puppy) ->
+ io:format("Puppy: ~p~n", [Puppy:name()])
+ end, Breed:puppies())
+```
Querying
--------
You can search the database with the boss_db:find functions. Example:
- Puppies = boss_db:find(puppy, [{breed_id, 'equals', "breed-47"}])
+```erlang
+Puppies = boss_db:find(puppy, [{breed_id, 'equals', "breed-47"}])
+```
This is somewhat verbose. If you compile the source file with boss_compiler,
you'll be able to write the more simple expression:
- Puppies = boss_db:find(puppy, [breed_id = "breed-47"])
+```erlang
+Puppies = boss_db:find(puppy, [breed_id = "breed-47"])
+```
BossDB supports many query operators, as well as sorting, offsets, and limits;
see the API references at the top.
@@ -160,27 +180,33 @@ Validating and saving
To create and save a new record, you would write:
- Breed = breed:new(id, "Golden Retriever"),
- {ok, SavedBreed} = Breed:save()
+```erlang
+Breed = breed:new(id, "Golden Retriever"),
+{ok, SavedBreed} = Breed:save()
+```
You can provide validation logic by adding a validation_tests/0 function
to your model file, e.g.
- -module(breed, [Id, Name]).
- -has({puppies, many}).
- -export([validation_tests/0]).
+```erlang
+-module(breed, [Id, Name]).
+-has({puppies, many}).
+-export([validation_tests/0]).
- validation_tests() ->
- [{fun() -> length(Name) > 0 end,
- "Name must not be empty!"}].
+validation_tests() ->
+ [{fun() -> length(Name) > 0 end,
+ "Name must not be empty!"}].
+```
If validation fails, the save/0 function will return a list of error messages
instead of the saved record.
You can also provide spec strings in the parameter declaration if you want to
validate the attribute types before saving, e.g.
- -module(puppy, [Id, Name::string(), BirthDate::datetime()]).
+```erlang
+-module(puppy, [Id, Name::string(), BirthDate::datetime()]).
+```
Accepted types are:
@@ -205,9 +231,11 @@ You may want to override these defaults if you are working with an existing
database. To specify your own column and table names, you can use the
-columns() and -table() attributes in a model file like so:
- -module(puppy, [Id, Name]).
- -columns([{id, "puppy_id"}, {name, "puppy_name"}]).
- -table("puppy_table").
+```erlang
+-module(puppy, [Id, Name]).
+-columns([{id, "puppy_id"}, {name, "puppy_name"}]).
+-table("puppy_table").
+```
Events
------
@@ -216,13 +244,15 @@ BossDB provides two kinds of model events: synchronous save hooks, and
asynchronous notifications via BossNews. Save hooks are simple; just
define one or more of these functions in your model file:
- before_create/0 -> ok | {ok, ModifiedRecord} | {error, Reason}
- before_update/0 -> ok | {ok, ModifiedRecord} | {error, Reason}
- before_update/1 -> ok | {ok, ModifiedRecord} | {error, Reason}
- after_create/0
- after_update/0
- after_update/1
- before_delete/0 -> ok | {error, Reason}
+```erlang
+before_create/0 -> ok | {ok, ModifiedRecord} | {error, Reason}
+before_update/0 -> ok | {ok, ModifiedRecord} | {error, Reason}
+before_update/1 -> ok | {ok, ModifiedRecord} | {error, Reason}
+after_create/0
+after_update/0
+after_update/1
+before_delete/0 -> ok | {error, Reason}
+```
The before_update/1 and after_update/1 hooks provide access to the old
boss record as an additional parameter. If both hooks like before_update/0
@@ -235,15 +265,18 @@ not have to wait for callbacks to complete. The central concept in BossNews
is a "watch", which is an event observer. You can create and destroy watches
programmatically:
- {ok, WatchId} = boss_news:watch(TopicString, CallBack),
- boss_news:cancel_watch(WatchId)
-
+```
+{ok, WatchId} = boss_news:watch(TopicString, CallBack),
+boss_news:cancel_watch(WatchId)
+```
Four kinds of topic strings are supported:
- "puppies" => watch for new and deleted Puppy records
- "puppy-42.*" => watch all attributes of Puppy #42
- "puppy-*.name" => watch the "name" attribute of all Puppy records
- "puppy-*.*" => watch all attributes of all Puppy records
+```erlang
+"puppies" => watch for new and deleted Puppy records
+"puppy-42.*" => watch all attributes of Puppy #42
+"puppy-*.name" => watch the "name" attribute of all Puppy records
+"puppy-*.*" => watch all attributes of all Puppy records
+```
The callback is passed two or three arguments: the event name
(created/updated/deleted), information about the event (i.e. the new and old
@@ -253,10 +286,12 @@ third argument to boss_news:watch/3.
BossNews is suited to providing real-time notifications and alerts. For example,
if you want to log each time a puppy's name is changed,
- boss_news:watch("puppy-*.name",
- fun(updated, {Puppy, 'name', OldName, NewName}) ->
- error_logger:info_msg("Puppy's name changed from ~p to ~p", [OldName, NewName])
- end)
+```erlang
+boss_news:watch("puppy-*.name",
+ fun(updated, {Puppy, 'name', OldName, NewName}) ->
+ error_logger:info_msg("Puppy's name changed from ~p to ~p", [OldName, NewName])
+ end)
+```
For more details see the documentation at http://www.chicagoboss.org/doc/api-news.html

0 comments on commit a672496

Please sign in to comment.