package sihl

  1. Overview
  2. Docs

Source file gen_core.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
152
153
154
155
156
157
type gen_type =
  | Float
  | Int
  | Bool
  | String
  | Datetime

let gen_type_to_example = function
  | Float -> "0.3"
  | Int -> "10"
  | Bool -> "true"
  | String -> {|"foobar"|}
  | Datetime -> "(Ptime.of_float_s 1.0 |> Option.get)"
;;

let ocaml_type_of_gen_type = function
  | Float -> "float"
  | Int -> "int"
  | Bool -> "bool"
  | String -> "string"
  | Datetime -> "Ptime.t"
;;

let caqti_type_of_gen_type = function
  | Float -> "float"
  | Int -> "int"
  | Bool -> "bool"
  | String -> "string"
  | Datetime -> "ptime"
;;

let conformist_type_of_gen_type = function
  | Float -> "float"
  | Int -> "int"
  | Bool -> "bool"
  | String -> "string"
  | Datetime -> "datetime"
;;

let gen_type_of_string (s : string) : (gen_type, string) result =
  match s with
  | "float" -> Ok Float
  | "int" -> Ok Int
  | "bool" -> Ok Bool
  | "string" -> Ok String
  | "datetime" -> Ok Datetime
  | s -> Error (Format.sprintf "Invalid type '%s' provided" s)
;;

type schema = (string * gen_type) list

let schema_of_string (s : string list) : (schema, string) result =
  s
  |> List.map (String.split_on_char ':')
  |> List.map (fun s ->
         match s with
         | [ name; type_ ] -> Ok (name, type_)
         | _ ->
           Error
             (Format.sprintf
                "Invalid input provided '%s'"
                (String.concat ":" s)))
  |> List.fold_left
       (fun schema next ->
         match schema, next with
         | Ok schema, Ok (name, type_) ->
           (match gen_type_of_string type_ with
           | Ok gen_type -> Ok (List.cons (name, gen_type) schema)
           | Error msg -> Error msg)
         | Error msg, _ -> Error msg
         | Ok _, Error msg -> Error msg)
       (Result.ok [])
  |> Result.map List.rev
;;

type file =
  { name : string
  ; template : string
  ; params : (string * string) list
  }

let render { template; params; _ } =
  List.fold_left
    (fun res (name, value) ->
      CCString.replace
        ~which:`All
        ~sub:(Format.sprintf "{{%s}}" name)
        ~by:value
        res)
    template
    params
;;

let write_file (file : file) (path : string) : unit =
  let content = render file in
  let filepath = Format.sprintf "%s/%s" path file.name in
  try
    Bos.OS.File.write (Fpath.of_string filepath |> Result.get_ok) content
    |> Result.get_ok;
    print_endline (Format.sprintf "Wrote file '%s'" filepath)
  with
  | _ ->
    let msg = Format.sprintf "Failed to write file '%s'" filepath in
    print_endline msg;
    failwith msg
;;

let write_files_and_create_dir path files =
  Bos.OS.Dir.create (Fpath.of_string path |> Result.get_ok) |> ignore;
  List.iter (fun file -> write_file file path) files
;;

let write_in_domain (context : string) (files : file list) : unit =
  let root = Core_configuration.root_path () |> Option.get in
  let model_path = Format.sprintf "%s/app/domain/%s" root context in
  match Bos.OS.Dir.exists (Fpath.of_string model_path |> Result.get_ok) with
  | Ok true -> failwith (Format.sprintf "Model '%s' exists already" model_path)
  | Ok false | Error _ -> write_files_and_create_dir model_path files
;;

let write_in_test (name : string) (files : file list) : unit =
  let root = Core_configuration.root_path () |> Option.get in
  let test_path = Format.sprintf "%s/test/%s" root name in
  match Bos.OS.Dir.exists (Fpath.of_string test_path |> Result.get_ok) with
  | Ok true -> failwith (Format.sprintf "Test '%s' exists already" test_path)
  | Ok false | Error _ -> write_files_and_create_dir test_path files
;;

let write_in_database (file : file) : unit =
  let root = Core_configuration.root_path () |> Option.get in
  let path = Format.sprintf "%s/database" root in
  Bos.OS.Dir.create (Fpath.of_string path |> Result.get_ok) |> ignore;
  List.iter (fun file -> write_file file path) [ file ]
;;

let write_in_view (name : string) (files : file list) : unit =
  let root = Core_configuration.root_path () |> Option.get in
  let view_path = Format.sprintf "%s/web/view/%s" root name in
  match Bos.OS.Dir.exists (Fpath.of_string view_path |> Result.get_ok) with
  | Ok true -> failwith (Format.sprintf "View '%s' exists already" view_path)
  | Ok false | Error _ -> write_files_and_create_dir view_path files
;;

type database =
  | MariaDb
  | PostgreSql

let database_of_string = function
  | "mariadb" -> MariaDb
  | "postgresql" -> PostgreSql
  | database ->
    failwith
      (Format.sprintf
         "Invalid database provided '%s', only 'mariadb' and 'postgresql' \
          supported"
         database)
;;
OCaml

Innovation. Community. Security.