Packages
krug
1.0.0
2.0.36
2.0.35
2.0.34
2.0.33
2.0.32
2.0.31
2.0.30
2.0.29
2.0.27
2.0.26
2.0.25
2.0.24
2.0.23
2.0.22
2.0.20
2.0.19
2.0.18
2.0.17
2.0.16
2.0.15
2.0.14
2.0.13
2.0.12
2.0.11
2.0.10
2.0.9
2.0.8
2.0.7
2.0.6
2.0.5
2.0.4
2.0.1
2.0.0
1.1.53
1.1.52
1.1.50
1.1.49
1.1.48
1.1.47
1.1.46
1.1.45
1.1.44
1.1.43
1.1.42
1.1.41
1.1.40
1.1.39
1.1.38
1.1.37
1.1.36
1.1.35
1.1.34
1.1.33
1.1.32
1.1.31
1.1.30
1.1.29
1.1.28
1.1.27
1.1.26
1.1.25
1.1.24
1.1.23
1.1.22
1.1.21
1.1.20
1.1.19
1.1.18
1.1.17
1.1.16
1.1.15
1.1.14
1.1.12
1.1.10
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.9
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.31
0.4.30
0.4.29
0.4.28
0.4.27
0.4.26
0.4.25
0.4.24
0.4.23
0.4.22
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.1
0.2.0
0.1.0
A Utilitary package functionalities modules for improve a secure performatic development.
Current section
Files
Jump to
Current section
Files
lib/krug/ecto/base.ecto.dao.ex
defmodule Krug.BaseEctoDAO do
@moduledoc """
Defines a behaviour for higher-level CRUD functionalities module
to facilitate the raw queries usage with Ecto.
Utilization: Create a module that extends ```Krug.BaseEctoDAO```.
- ```MyApp.App.Repo``` should be a module that extends Ecto.Repo. (Required)
- ```ets_key```should be an atom thats identifier the ETS table for caching. (Required)
```elixir
defmodule MyApp.App.DAOService do
use Krug.BaseEctoDAO, repo: MyApp.App.Repo, ets_key: :my_ets_key_atom_identifier
end
```
This mechanism also includes by default a in-memory query cache
of last ```cache_objects_per_table``` (default to 10) select results of each database table.
This cache (for respective table) is empty each time that a entry
is inserted/updated/deleted from the respective table.
You can disable this mechanism for expensive tables (large text data or many columns),
or tables that are very intensible/frequently writed/updated.
For this use the ```nocache_tables``` atribute.
```elixir
defmodule MyApp.App.DAOService do
use Krug.BaseEctoDAO,
repo: MyApp.App.Repo,
nocache_tables: ["my_table_no_cache1","my_table_no_cache2"],
cache_objects_per_table: 10,
ets_key: :my_ets_key_atom_identifier
end
```
"""
@moduledoc since: "0.2.0"
@doc """
Load a resultset from a table. Return nil only if fail in execution of SQL command.
To see how handle returned resultset, search by ```Krug.ResultSetHandler```
in this documentation.
## Examples
```elixir
iex > sql = "select id, name, email, age, address from person limit 10"
iex > MyApp.App.DAOService.load(sql)
%MyXQL.Result{
columns: ["id", "name", "email", "age", "address"],
connection_id: 1515,
last_insert_id: 0,
num_rows: 1,
num_warnings: 0,
rows: [
[1,"Johannes Backend","johannes@backend.com",54,"404 street"]
]
}
```
```elixir
iex > sql = "select id, columnThatNonExists, email, age, address from person limit 10"
iex > MyApp.App.DAOService.load(sql)
nil
```
"""
@callback load(sql :: String.t()) :: map
@doc """
Load a resultset from a table. Return nil only if fail in execution of SQL command.
To see how handle returned resultset, search by ```Krug.ResultSetHandler```
in this documentation.
## Examples
```elixir
iex > sql = "select id, name, email, age, address from person where age < ?"
iex > MyApp.App.DAOService.load(sql,[20])
%MyXQL.Result{
columns: ["id", "name", "email", "age", "address"],
connection_id: 1515,
last_insert_id: 0,
num_rows: 0,
num_warnings: 0,
rows: nil
}
```
```elixir
iex > sql = "select id, columnThatNotExists, email, age, address from person where age < ?"
iex > MyApp.App.DAOService.load(sql,[20])
nil
```
"""
@callback load(sql :: String.t(),params :: Enum.t()) :: map
@doc """
Insert a new row on a table. Return false only if fail in execution of SQL command.
## Examples
```elixir
iex > sql = "insert into person(name,email,age,address) values (?,?,?,?)"
iex > MyApp.App.DAOService.insert(sql,["Johannes Backend 2"])
false
```
```elixir
iex > sql = "insert into person(name,email,age,address) values (?,?,?,?)"
iex > MyApp.App.DAOService.insert(sql,["Johannes Backend 2","johannes@backend.com",54,"404 street"])
true
```
"""
@callback insert(sql :: String.t(),params :: Enum.t()) :: boolean
@doc """
Update a row on a table. Return false only if fail in execution of SQL command.
## Examples
```elixir
iex > sql = "update person set name = ?, email = ? where id = ?"
iex > MyApp.App.DAOService.update(sql,["Johannes Backend 3","johannes@has.not.email",1])
true
```
```elixir
iex > sql = "update person set columnThatNotExists = ?, email = ? where id = ?"
iex > MyApp.App.DAOService.update(sql,["Johannes Backend 3","johannes@has.not.email",1])
false
```
"""
@callback update(sql :: String.t(),params :: Enum.t()) :: boolean
@doc """
Delete a row from a table. Return false only if fail in execution of SQL command.
## Examples
```elixir
iex > sql = "delete from person where name = ? and id = ?"
iex > MyApp.App.DAOService.delete(sql,["Person Name That Not Exist",1000000000000001])
true
```
```elixir
iex > sql = "delete from person where columnThatNotExists = ?"
iex > MyApp.App.DAOService.delete(sql,["Johannes Backend 3"])
false
```
"""
@callback delete(sql :: String.t(),params :: Enum.t()) :: boolean
defmacro __using__(opts) do
quote bind_quoted: [opts: opts] do
alias Krug.BaseEctoDAOSqlCache
alias Krug.BaseEctoDAOUtil
alias Krug.StringUtil
@behaviour Krug.BaseEctoDAO
@repo Keyword.get(opts,:repo)
@nocache_tables Keyword.get(opts,:nocache_tables)
@cache_objects_per_table Keyword.get(opts,:cache_objects_per_table)
@ets_key Keyword.get(opts,:ets_key)
@impl Krug.BaseEctoDAO
def load(sql,params \\[]) do
normalized_sql = sql |> BaseEctoDAOUtil.normalize_sql()
table_name = normalized_sql |> BaseEctoDAOUtil.extract_table_name()
cond do
(table_name |> use_cache()) -> load_with_cache(normalized_sql,params)
true -> load_without_cache(normalized_sql,params)
end
end
@impl Krug.BaseEctoDAO
def insert(sql,params) do
cud_operation(sql,params)
end
@impl Krug.BaseEctoDAO
def update(sql,params) do
cud_operation(sql,params)
end
@impl Krug.BaseEctoDAO
def delete(sql,params) do
cud_operation(sql,params)
end
defp cud_operation(sql,params) do
normalized_sql = sql |> BaseEctoDAOUtil.normalize_sql()
table_name = normalized_sql |> BaseEctoDAOUtil.extract_table_name()
ok = normalized_sql |> execute_sql(params,true)
cond do
(!ok) -> ok
(table_name |> use_cache())
-> BaseEctoDAOSqlCache.clear_cache(@ets_key)
true -> ok
end
end
defp load_without_cache(normalized_sql,params \\[]) do
execute_sql(normalized_sql,params,false)
end
defp load_with_cache(normalized_sql,params \\[]) do
resultset = BaseEctoDAOSqlCache.load_from_cache(@ets_key,normalized_sql,params)
cond do
(nil != resultset) -> resultset
true -> load_and_put_to_cache(normalized_sql,params)
end
end
defp load_and_put_to_cache(normalized_sql,params) do
resultset = execute_sql(normalized_sql,params,false)
cond do
(nil != resultset)
-> BaseEctoDAOSqlCache.put_cache(@ets_key,normalized_sql,params,resultset,
@cache_objects_per_table)
true -> nil
end
end
defp get_cache_size() do
cond do
(nil == @cache_objects_per_table or !(@cache_objects_per_table > 0)) -> 10
true -> @cache_objects_per_table
end
end
defp execute_sql(sql,params,bool_result) do
Ecto.Adapters.SQL.query(@repo,sql,params) |> handle_query_result(bool_result)
end
defp handle_query_result({:ok, result},bool_result) do
cond do
(bool_result) -> true
true -> result
end
end
defp handle_query_result({:error, _reason},bool_result) do
cond do
(bool_result) -> false
true -> nil
end
end
defp use_cache(table_name) do
cond do
(nil == @nocache_tables or Enum.empty?(@nocache_tables)) -> true
(Enum.member?(@nocache_tables,table_name)) -> false
true -> true
end
end
end
end
end