Skip to content

Commit ffc7f66

Browse files
authored
Merge pull request #19 from JuliaPostgresORM/generate-typescript
Generate typescript
2 parents ea3cbe3 + 6ebac90 commit ffc7f66

File tree

4 files changed

+354
-166
lines changed

4 files changed

+354
-166
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "PostgresORM"
22
uuid = "748b5efa-ed57-4836-b183-a38105a77fdd"
33
authors = ["Vincent Laugier <vincent.laugier@gmail.com>"]
4-
version = "0.1.7"
4+
version = "0.3.0"
55

66
[deps]
77
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"

src/Tool/Tool-typescript.jl

Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
function generate_typescript_code(dbconn::LibPQ.Connection,
2+
outdir::String,
3+
relative_path_to_enum_dir::String
4+
;lang_code = "eng",
5+
module_name_for_all_schemas::Union{String,Missing} = "Model")
6+
7+
object_model = generate_object_model(
8+
dbconn,
9+
lang_code,
10+
module_name_for_all_schemas = module_name_for_all_schemas
11+
)
12+
13+
generate_typescript_enums_from_object_model(object_model, outdir)
14+
15+
generate_typescript_classes_from_object_model(object_model,
16+
outdir,
17+
relative_path_to_enum_dir)
18+
19+
end
20+
21+
22+
function generate_typescript_enums_from_object_model(object_model::Dict, outdir::String)
23+
24+
outdir = joinpath(outdir,"enum")
25+
26+
if !isdir(outdir)
27+
mkpath(outdir)
28+
end
29+
30+
enums = object_model[:enums]
31+
32+
for e in enums
33+
34+
type_name = e[:type_name]
35+
file_path = joinpath(outdir,"$type_name.ts")
36+
37+
content = "export enum $type_name {\n\n"
38+
39+
for (idx,v) in enumerate(e[:values])
40+
content *= " $v = $idx, \n"
41+
end
42+
43+
content *= "\n"
44+
content *= "}" # close enum
45+
46+
write(file_path,content)
47+
end
48+
49+
50+
51+
end
52+
53+
"""
54+
get_typescript_type_of_elt_type(julia_elt_type::String)
55+
56+
Eg. Model.Patient returns Patient
57+
"""
58+
function get_typescript_type_of_elt_type(julia_elt_type::String)
59+
60+
julia_elt_type = (last split)(julia_elt_type,".")
61+
62+
typescript_elt_type = try
63+
basic_elt_type = eval(Symbol(julia_elt_type))
64+
if basic_elt_type == Bool
65+
typescript_elt_type = "boolean"
66+
elseif basic_elt_type == String
67+
typescript_elt_type = "string"
68+
elseif (basic_elt_type <: Date
69+
|| basic_elt_type <: DateTime
70+
|| basic_elt_type <: ZonedDateTime)
71+
typescript_elt_type = "Date"
72+
elseif basic_elt_type <: Number
73+
typescript_elt_type = "number"
74+
end
75+
catch e
76+
typescript_elt_type = julia_elt_type
77+
end
78+
return typescript_elt_type
79+
end
80+
81+
"""
82+
get_typescript_elt_type(_field::Dict)
83+
84+
Eg. Vector{Model.Patient} returns Patient
85+
"""
86+
function get_typescript_elt_type(_field::Dict)
87+
chop(get_typescript_type(_field), tail = 2) # Remove the trailing '[]'
88+
end
89+
90+
"""
91+
get_typescript_type(_field::Dict)
92+
93+
Eg. Vector{Model.Patient} returns Patient[]
94+
"""
95+
function get_typescript_type(_field::Dict)
96+
97+
_regexVector = r"Vector{([a-zA-Z0-9._]+)}"
98+
99+
if (_m = match(_regexVector, _field[:field_type])) |> !isnothing
100+
elt_type_name = _m |>
101+
n -> string(n.captures[1])
102+
typescript_elt_type = get_typescript_type_of_elt_type(elt_type_name)
103+
return "$typescript_elt_type[]"
104+
else
105+
return get_typescript_type_of_elt_type(_field[:field_type])
106+
end
107+
108+
end
109+
110+
111+
function generate_typescript_classes_from_object_model(object_model::Dict,
112+
outdir::String,
113+
relative_path_to_enum_dir::String)
114+
115+
outdir = joinpath(outdir,"classes")
116+
117+
modules = object_model[:modules]
118+
structs = object_model[:structs]
119+
fields = object_model[:fields]
120+
121+
# Reset content
122+
for _struct in structs
123+
_struct[:struct_content] = ""
124+
end
125+
126+
# ################ #
127+
# Open the struct #
128+
# ################ #
129+
for _struct in structs
130+
str = "export class $(_struct[:name]) {\n\n"
131+
_struct[:struct_content] *= str
132+
end
133+
134+
# ################## #
135+
# Declare the fields #
136+
# ################## #
137+
for f in fields
138+
139+
if !haskey(f,:struct)
140+
@error f
141+
return
142+
end
143+
144+
_struct = f[:struct]
145+
146+
field_name = f[:name]
147+
typescript_type = get_typescript_type(f)
148+
str = " $field_name:$typescript_type;\n"
149+
_struct[:struct_content] *= str
150+
end
151+
152+
# #################### #
153+
# Open the constructor #
154+
# #################### #
155+
for _struct in structs
156+
str = "\n"
157+
str *= " constructor(_json:Object) {\n"
158+
_struct[:struct_content] *= str
159+
end
160+
161+
# ####################################################### #
162+
# Add the arguments declaration of the second constructor #
163+
# ####################################################### #
164+
for f in fields
165+
166+
_struct = f[:struct]
167+
168+
field_name = f[:name]
169+
indent = repeat(" ", 8)
170+
str = ""
171+
if (f[:is_onetoone] || f[:is_manytoone])
172+
str *= indent * "if (_json['$field_name'] != null) {\n"
173+
str *= indent * " " * "this.$field_name = new $(get_typescript_type_of_elt_type(f[:field_type]))(_json['$field_name']);\n"
174+
str *= indent * "}\n"
175+
elseif f[:is_onetomany]
176+
elt_type = get_typescript_elt_type(f)
177+
str *= indent * "if (_json['$field_name'] != null) {\n"
178+
str *= indent * " " * "for (let e of _json['$field_name']) {\n"
179+
str *= indent * " " * "this.$field_name.push(new $elt_type(e));\n"
180+
str *= indent * " " * "}\n"
181+
str *= indent * "}\n"
182+
elseif f[:is_enum]
183+
str *= indent * "if (_json['$field_name'] != null) {\n"
184+
str *= indent * " " * "this.$field_name = Number($(get_typescript_type_of_elt_type(f[:field_type]))[_json['$field_name']]);\n"
185+
str *= indent * "}\n"
186+
elseif f[:is_vectorofenum]
187+
elt_type = get_typescript_elt_type(f)
188+
str *= indent * "if (_json['$field_name'] != null) {\n"
189+
str *= indent * " " * "for (let e of _json['$field_name']) {\n"
190+
str *= indent * " " * "this.$field_name.push(Number($elt_type[e]));\n"
191+
str *= indent * " " * "}\n"
192+
str *= indent * "}\n"
193+
else
194+
str *= indent * "this.$field_name = _json['$field_name'];\n"
195+
end
196+
_struct[:struct_content] *= str
197+
end
198+
199+
# ############################ #
200+
# Close the constructor #
201+
# ############################ #
202+
for _struct in structs
203+
str = " }\n"
204+
_struct[:struct_content] *= str
205+
end
206+
207+
# ################################################# #
208+
# Initialize the vector of imports for every struct #
209+
# ################################################# #
210+
for _struct in structs
211+
_struct[:imports] = []
212+
end
213+
214+
# ######################################################## #
215+
# Add the imports for enums, vetors of enum, complex types #
216+
# ######################################################## #
217+
for f in fields
218+
219+
_struct = f[:struct]
220+
if (f[:is_onetoone] || f[:is_manytoone])
221+
elt_type = get_typescript_type_of_elt_type(f[:field_type])
222+
pathToImport = joinpath("./",elt_type)
223+
push!(
224+
_struct[:imports],
225+
"import { $elt_type } from \"$pathToImport\""
226+
)
227+
elseif f[:is_onetomany]
228+
elt_type = get_typescript_elt_type(f)
229+
pathToImport = joinpath("./",elt_type)
230+
push!(
231+
_struct[:imports],
232+
"import { $elt_type } from \"$pathToImport\""
233+
)
234+
elseif f[:is_enum]
235+
elt_type = get_typescript_type_of_elt_type(f[:field_type])
236+
pathToImport = joinpath(relative_path_to_enum_dir,elt_type)
237+
push!(
238+
_struct[:imports],
239+
"import { $elt_type } from \"$pathToImport\""
240+
)
241+
elseif f[:is_vectorofenum]
242+
elt_type = get_typescript_elt_type(f)
243+
pathToImport = joinpath(relative_path_to_enum_dir,elt_type)
244+
push!(
245+
_struct[:imports],
246+
"import { $elt_type } from \"$pathToImport\""
247+
)
248+
end
249+
250+
end
251+
# Add the string of imports
252+
for _struct in structs
253+
if length(_struct[:imports]) > 0
254+
stringOfImports = join(unique(_struct[:imports]),";\n") * ";\n\n"
255+
_struct[:struct_content] = stringOfImports * _struct[:struct_content]
256+
end
257+
end
258+
259+
# ################ #
260+
# Close the struct #
261+
# ################ #
262+
for _struct in structs
263+
str = "\n} "
264+
_struct[:struct_content] *= str
265+
end
266+
267+
# ############## #
268+
# Write to files #
269+
# ############## #
270+
271+
# Empty the modules dirs
272+
for _module in modules
273+
module_dir = joinpath(outdir,_module[:name])
274+
rm(module_dir, recursive=true, force = true)
275+
mkpath(module_dir)
276+
end
277+
278+
279+
# Write the content of structs to files
280+
for _struct in structs
281+
module_dir = joinpath(outdir,_struct[:module][:name])
282+
if !isdir(module_dir)
283+
mkpath(module_dir)
284+
end
285+
file_path = joinpath(module_dir,"$(_struct[:name]).ts")
286+
write(file_path,_struct[:struct_content])
287+
end
288+
289+
end

0 commit comments

Comments
 (0)