11#!/usr/bin/env python3
2+ import pathlib
23
34import inflection
45
5- from lib .renderer import Renderer
6- from lib .dbscheme import *
76from lib import paths , schema , generator
7+ from lib .dbscheme import *
88
99log = logging .getLogger (__name__ )
1010
1111
1212def dbtype (typename ):
13+ """ translate a type to a dbscheme counterpart, using `@lower_underscore` format for classes """
1314 if typename [0 ].isupper ():
1415 return "@" + inflection .underscore (typename )
1516 return typename
1617
1718
1819def cls_to_dbscheme (cls : schema .Class ):
20+ """ Yield all dbscheme entities needed to model class `cls` """
1921 if cls .derived :
2022 yield DbUnion (dbtype (cls .name ), (dbtype (c ) for c in cls .derived ))
21- if not cls .derived or any (f .is_single () for f in cls .fields ):
23+ # output a table specific to a class only if it is a leaf class or it has 1-to-1 properties
24+ # Leaf classes need a table to bind the `@` ids
25+ # 1-to-1 properties are added to a class specific table
26+ # in other cases, separate tables are used for the properties, and a class specific table is unneeded
27+ if not cls .derived or any (f .is_single for f in cls .properties ):
2228 binding = not cls .derived
2329 keyset = DbKeySet (["id" ]) if cls .derived else None
2430 yield DbTable (
@@ -27,11 +33,12 @@ def cls_to_dbscheme(cls: schema.Class):
2733 columns = [
2834 DbColumn ("id" , type = dbtype (cls .name ), binding = binding ),
2935 ] + [
30- DbColumn (f .name , dbtype (f .type )) for f in cls .fields if f .is_single ()
36+ DbColumn (f .name , dbtype (f .type )) for f in cls .properties if f .is_single
3137 ]
3238 )
33- for f in cls .fields :
34- if f .is_optional ():
39+ # use property-specific tables for 1-to-many and 1-to-at-most-1 properties
40+ for f in cls .properties :
41+ if f .is_optional :
3542 yield DbTable (
3643 keyset = DbKeySet (["id" ]),
3744 name = inflection .tableize (f"{ cls .name } _{ f .name } " ),
@@ -40,7 +47,7 @@ def cls_to_dbscheme(cls: schema.Class):
4047 DbColumn (f .name , dbtype (f .type )),
4148 ],
4249 )
43- elif f .is_repeated () :
50+ elif f .is_repeated :
4451 yield DbTable (
4552 keyset = DbKeySet (["id" , "index" ]),
4653 name = inflection .tableize (f"{ cls .name } _{ f .name } " ),
@@ -52,24 +59,31 @@ def cls_to_dbscheme(cls: schema.Class):
5259 )
5360
5461
55- def generate (opts ):
62+ def get_declarations (data : schema .Schema ):
63+ return [d for cls in data .classes .values () for d in cls_to_dbscheme (cls )]
64+
65+
66+ def get_includes (data : schema .Schema , include_dir : pathlib .Path ):
67+ includes = []
68+ for inc in data .includes :
69+ inc = include_dir / inc
70+ with open (inc ) as inclusion :
71+ includes .append (DbSchemeInclude (src = inc .relative_to (paths .swift_dir ), data = inclusion .read ()))
72+ return includes
73+
74+
75+ def generate (opts , renderer ):
5676 input = opts .schema .resolve ()
5777 out = opts .dbscheme .resolve ()
58- renderer = Renderer (opts .check )
5978
6079 with open (input ) as src :
6180 data = schema .load (src )
6281
63- declarations = [d for cls in data .classes .values () for d in cls_to_dbscheme (cls )]
82+ dbscheme = DbScheme (src = input .relative_to (paths .swift_dir ),
83+ includes = get_includes (data , include_dir = input .parent ),
84+ declarations = get_declarations (data ))
6485
65- includes = []
66- for inc in data .includes :
67- inc = input .parent / inc
68- with open (inc ) as inclusion :
69- includes .append ({"src" : inc .relative_to (paths .swift_dir ), "data" : inclusion .read ()})
70- renderer .render ("dbscheme" , out , includes = includes , src = input .relative_to (paths .swift_dir ),
71- declarations = declarations )
72- return renderer .written
86+ renderer .render ("dbscheme" , out , dbscheme )
7387
7488
7589if __name__ == "__main__" :
0 commit comments