package sihl

  1. Overview
  2. Docs

Source file gen_model.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
let ml_template =
  {|
include Entity

exception Exception of string

let clean =
  if Sihl.Configuration.is_production ()
  then
    raise
    @@ Exception
         "Could not clean repository in production, this is most likely not what \
          you want."
  else Repo.clean
;;

let find id = Repo.find id
let search ?filter ?(sort = `Desc) ?(limit = 50) ?(offset = 0) () = Repo.search filter sort ~limit ~offset

let insert ({{name}} : t) =
  let open Lwt.Syntax in
  let* () = Repo.insert {{name}} in
  let* inserted = Repo.find {{name}}.id in
  (match inserted with
  | Some {{name}} -> Lwt.return (Ok {{name}})
  | None ->
    Logs.err (fun m ->
        m "Failed to insert {{name}} '%a'" pp {{name}});
    Lwt.return @@ Error "Failed to insert {{name}}")
;;

let create {{create_args}} : (t, string) Result.t Lwt.t =
  insert @@ create {{create_args}}
 ;;

let update id ({{name}} : t) =
  let open Lwt.Syntax in
  let {{name}} = { {{name}} with id } in
  let* () = Repo.update {{name}} in
  let* updated = find id in
  match updated with
  | Some updated -> Lwt.return (Ok updated)
  | None -> Lwt.return @@ Error "Failed to update {{name}}"
;;

let delete ({{name}} : t) =
  Repo.delete {{name}} |> Lwt.map Result.ok
;;
|}
;;

let mli_template =
  {|
type t =
  { id : string
  {{entity_type}}
  ; created_at : Ptime.t
  ; updated_at : Ptime.t
  }
[@@deriving show]

val schema : (unit, {{ctor_type}} -> t, t) Conformist.t

exception Exception of string

val clean : unit -> unit Lwt.t
val find : string -> t option Lwt.t
  val search
    :  ?filter:string
    -> ?sort:[ `Desc | `Asc ]
    -> ?limit:int
    -> ?offset:int
    -> unit
    -> (t list * int) Lwt.t
val create : {{ctor_type}} -> (t, string) result Lwt.t
val insert : t -> (t, string) result Lwt.t
val update : string -> t -> (t, string) result Lwt.t
val delete : t -> (unit, string) result Lwt.t
|}
;;

let dune_file_template database =
  let open Gen_core in
  match database with
  | PostgreSql ->
    {|(library
 (name {{name}})
 (libraries caqti-driver-postgresql sihl service)
 (preprocess
  (pps ppx_deriving.show)))
|}
  | MariaDb ->
    {|(library
 (name {{name}})
 (libraries caqti-driver-mariadb sihl service)
 (preprocess
  (pps ppx_deriving.show)))
|}
;;

let generate (database : string) (name : string) (schema : Gen_core.schema)
    : unit
  =
  let database = Gen_core.database_of_string database in
  if String.contains name ':'
  then failwith "Invalid service name provided, it can not contain ':'"
  else (
    let create_args =
      schema |> List.map (fun (name, _) -> name) |> String.concat " "
    in
    let ml_filename = Format.sprintf "%s.ml" name in
    let ml_parameters = [ "name", name; "create_args", create_args ] in
    let mli_filename = Format.sprintf "%s.mli" name in
    let mli_parameters =
      [ "entity_type", Gen_entity.entity_type schema
      ; "ctor_type", Gen_entity.ctor_type schema
      ]
    in
    let service_file =
      Gen_core.
        { name = ml_filename; template = ml_template; params = ml_parameters }
    in
    let service_interface_file =
      Gen_core.
        { name = mli_filename
        ; template = mli_template
        ; params = mli_parameters
        }
    in
    let entity_file = Gen_entity.file schema in
    let repo_file = Gen_repo.file database name schema in
    let dune_file =
      Gen_core.
        { name = "dune"
        ; template = dune_file_template database
        ; params = [ "name", name ]
        }
    in
    Gen_core.write_in_domain
      name
      [ service_file
      ; service_interface_file
      ; entity_file
      ; repo_file
      ; dune_file
      ];
    Gen_core.write_in_test
      name
      Gen_model_test.[ test_file name schema; dune_file name ]);
  Gen_migration.write_migration_file database name schema
;;
OCaml

Innovation. Community. Security.