Esempio n. 1
0
 def render_units(self):
     u = IndentString()
     [
         u.add(MasterDataStoreRenderUnit(table).render())
         for k, table in self.master_loader.iter()
     ]
     return u
Esempio n. 2
0
    def render_init(self):
        """
        イニシャライザの出力

        :return: IndexString
        """
        table = self.data
        # キー情報の取得
        hk = table.hash_key
        rk = table.range_key
        keys = [k.name for k in [hk, rk] if k is not None]
        # hashキーとrangeキーだけ明示的にパラメータとして定義する
        o = ', '.join(
            [f'{k}: {table.attributes[k].python_init_type_str} = None' for k in keys])
        if len(o) > 0:
            o = f'{o}, '

        body = IndentString(f'def __init__(self, {o}**kwargs):')
        body.add('super().__init__(**kwargs)')
        # 記述を短くするためにFieldクラスの参照を保持する
        body.add('ft = self.__class__.Field')

        is_alone = table.is_alone
        if not is_alone and rk is None:
            # 子テーブル且つレンジキーがない場合は単一子テーブルとなる
            parent = table.parent_table
            # 単一子テーブルのrangeキーの値は常にtagで固定
            body.add(f'self.{parent.range_key.name} = "{table.tag_name}"')

        # 各フィールドの初期化処理
        for key, attr in table.attributes.items():
            body.add(attr.gen_init_str())

        return body
Esempio n. 3
0
    def render_fields(self):
        """
        Fieldクラスの出力

        :return: IndexString
        """
        table = self.data
        # 継承元の決定
        is_alone = table.is_alone
        if table.is_alone:
            body = IndentString('class Field(SoloHatsudenkiTable.Field):')
        else:
            body = IndentString(f'class Field({table.parent_table.class_name}.Field):')

        attr_num = 0
        for key, attr in table.attributes.items():
            if attr.is_alias_key:
                # aliasキーなので実際のフィールドとしては存在しない
                continue
            body.add(attr.class_string)
            body.add(attr.gen_def_str())

            attr_num += 1

        # 属性が一つもない場合はpass
        if attr_num is 0:
            body.add('pass')
        return body
Esempio n. 4
0
    def render_units(self):
        ToolOutput.anchor('Wiki出力を開始')
        u = IndentString()
        for k, table in self.master_loader.iter():
            un = MasterDataWikiRenderUnit(table).render()
            u.add(un)
        ToolOutput.pop('OK')

        return u
Esempio n. 5
0
 def render_header(self) -> IndentString:
     u = IndentString()
     u.add('from hatsudenki.packages.cache.base import column')
     u.add('from hatsudenki.packages.cache.base.index import PrimaryIndex')
     u.add(
         'from hatsudenki.packages.master.model import MasterModelSolo, MasterModelMulti'
     )
     u.blank_line(2)
     return u
Esempio n. 6
0
    def cs_access_name(self):
        u = IndentString()
        t = self.get_target_table()

        u.add(f'public {t.class_name} {self.cs_name}Table()')
        u.indent('{')
        u.add(f'return {t.class_name}.Instance;')
        u.outdent('}')
        return u
Esempio n. 7
0
 def _get_list(self):
     hk = self.data.hash_key
     rk = self.data.range_key
     if rk is None:
         return None
     u = IndentString()
     n = f'{hk.cs_type_name} {hk.column_name}'
     u.add(f'public List<{self.record_type}> GetList({n})')
     u.indent('{')
     u.add(f'return _records[{hk.column_name}];')
     u.outdent('}')
     return u
Esempio n. 8
0
    def render_resolver(self):
        """
        リゾルバの出力

        :return: IndexString
        """
        # 今の所aliasキーのリゾルバしか無い
        body = IndentString()
        for k, attr in self.data.attributes.items():
            b = attr.resolver_string
            if b:
                body.add(b)

        return body
Esempio n. 9
0
 def render_header(self):
     u = IndentString()
     u.add('import enum')
     u.add(
         'from hatsudenki.packages.master.model import EnumResolver, MasterResolver'
     )
     u.blank_line(2)
     return u
Esempio n. 10
0
    def serial_resolver_default():
        i = IndentString()

        i.add('@property')
        i.indent('def log_id(self):')
        i.add('return self.one_cursor')

        return i
Esempio n. 11
0
    def _get(self):
        u = IndentString()
        hk = self.data.hash_key
        rk = self.data.range_key

        if rk:
            n = f'{hk.cs_type_name} {hk.column_name}, {rk.cs_type_name} {rk.column_name}'
            c = f'return _records[{hk.column_name}].Find(x => x.GetRangeKey() == {rk.column_name});'
        else:
            n = f'{hk.cs_type_name} {hk.column_name}'
            c = f'return _records[{hk.column_name}];'

        u.add(f'public {self.record_type} Get({n})')
        u.indent('{')
        u.add(f'{c}')
        u.outdent('}')
        return u
Esempio n. 12
0
 def _find(self, is_all: bool):
     if self.data.range_key is None:
         return None
     u = IndentString()
     hk = self.data.hash_key
     if is_all:
         t = f'List<{self.record_type}>'
         n = 'FindAll'
     else:
         t = self.record_type
         n = 'Find'
     u.add(
         f'public {t} {n}({hk.cs_type_name} {hk.column_name}, Predicate<{self.record_type}> func)'
     )
     u.indent('{')
     u.add(f'return _records[{hk.column_name}].{n}(func);')
     u.outdent('}')
     return u
Esempio n. 13
0
    def render(self):
        u = IndentString()
        u.add('|' + '|'.join(self.header) + '|')
        u.add('|' + '|'.join(['---------'] * len(self.header)) + '|')

        for row in self.rows:
            s = []
            for h in self.header:
                s.append(self._get(row.get(h, '----')))
            u.add('|' + '|'.join(s) + '|')
        return u
Esempio n. 14
0
    def serial_resolver_name(self):
        if not self.is_serial_key:
            return None

        serial = f"'{self.table_name}_'" + f' + str(self.{self.column_name}).zfill(10)'

        i = IndentString()

        i.add('@property')
        i.indent('def log_id(self):')
        i.add(f'return {serial}')

        return i
Esempio n. 15
0
    async def render_to_wiki(self, base_url, token_str):
        ToolOutput.anchor('Wiki出力を開始')

        wiki = GitWikiUploader(base_url, token_str)

        page_list = await wiki.get_page_list()
        page_slug_list = [v['slug'] for v in page_list]

        d: DefaultDict[str, List[MasterDataWikiRenderUnit]] = defaultdict(list)
        ToolOutput.anchor('YAML読み込み')
        for k, table in self.master_loader.iter():
            ru = MasterDataWikiRenderUnit(table)
            ToolOutput.out(f'{ru.page_name} # {ru.data.excel_sheet_name}')
            d[ru.page_name].append(ru)
        ToolOutput.pop('OK')

        ToolOutput.anchor('書き出し')
        num = 1
        index = MarkdownTableRenderer(
            ['ID', 'Book', 'Client', 'Server', 'Planner', 'Table'])
        for p, rus in d.items():
            ToolOutput.anchor(p)
            u = IndentString()
            for r in rus:
                u.add(r.render())
                idx = r.render_index()
                idx['ID'] = str(num)
                num += 1
                index.append(idx)

            if p in page_slug_list:
                ToolOutput.print(f'{p}更新します')
                await wiki.update_page(content=u.render(), page_name=p)
            else:
                ToolOutput.print(f'{p}作成します')
                await wiki.create_page(content=u.render(), page_name=p)
            ToolOutput.pop('OK')

        ix = self.render_index(index)

        index_title = 'MasterData/☆INDEX☆'
        if index_title in page_slug_list:
            ToolOutput.print(f'{index_title}更新します')
            await wiki.update_page(content=ix.render(), page_name=index_title)
        else:
            ToolOutput.print(f'{index_title}作成します')
            await wiki.create_page(content=ix.render(), page_name=index_title)

        ToolOutput.pop('OK')
Esempio n. 16
0
    def render(self):
        ToolOutput.anchor(f'{self.data.label} をMarkdownに変換')
        u = IndentString()
        u.add(f'# {self.data.excel_sheet_name}')
        u.add(f'## 情報')
        u.add(self.data.description if self.data.
              description else '*!! descriptionが設定されていません !!*')
        u.blank_line()

        u.add(self._gen_info().render())

        u.add(f'## 担当者')
        u.add(self._gen_assigner().render())

        u.add(f'## スキーマ情報')
        u.add(self._column().render())

        ToolOutput.pop('OK')
        return u
Esempio n. 17
0
    def _model(self):
        u = IndentString()
        u.add('[MessagePackObject]')
        u.add(f'public class {self.record_type}')
        u.indent('{')

        keys = [c for c in self.data.columns.values() if not c.is_no_pack]
        keys.extend(
            [c for c in self.data.shadow_columns.values() if not c.is_no_pack])

        args = ', '.join((c.cs_argument_name for c in keys))

        u.add(f'public {self.record_type}({args})')
        u.indent('{')
        [u.add(c.cs_assign_name) for c in keys]
        u.outdent('}')

        for idx, c in enumerate(keys):
            if c.is_no_pack:
                continue
            u.add(f'[Key({idx})]', c.cs_define_name)

        hk = self.data.hash_key
        u.add(f'public {hk.cs_type_name} GetHashKey()')
        u.indent('{')
        u.add(f'return {hk.cs_name};')
        u.outdent('}')

        rk = self.data.range_key
        if rk:
            u.add(f'public {rk.cs_type_name} GetRangeKey()')
            u.indent('{')
            u.add(f'return {rk.cs_name};')
            u.outdent('}')

        for c in keys:
            if not c.is_no_pack:
                u.add(c.cs_access_name())

        u.outdent('}')

        return u
Esempio n. 18
0
 def render_header(self):
     u = IndentString()
     u.add('using System;')
     u.add('using System.Collections.Generic;')
     u.add('using MessagePack;')
     return u
Esempio n. 19
0
 def render_index(self, index: MarkdownTableRenderer):
     ToolOutput.anchor('目次')
     u = IndentString()
     u.add('# MasterData目次')
     u.add(index.render())
     return u
Esempio n. 20
0
    def render(self, name):
        """
        クラス出力

        :param name: フィールド名
        :return: IndentString
        """
        u = IndentString()
        u.indent(f'class {name}(MarkedObject):')
        u.indent('class Field:')
        for k, v in self.attributes.items():
            u.add(v.class_string)
            u.add(v.gen_def_str())

        u.outdent()
        u.blank_line()
        u.indent('def __init__(self, name, parent: Markable, **kwargs):')
        u.add('super().__init__(name, parent)')
        u.add('ft = self.__class__.Field')
        for k, v in self.attributes.items():
            u.add(v.gen_init_str(direct_assign=False))

        u.add('')
        return u
Esempio n. 21
0
    def render(self, name):
        hash_key = next((v for k, v in self.attributes.items() if v.is_hash))

        u = IndentString()
        u.indent(f'class {name}(MarkedObjectWithIndex):')
        u.indent('class Meta:')
        u.add(f"hash_key = '{hash_key.name}'")
        u.outdent()
        u.blank_line()
        u.indent('class Field:')
        for k, v in self.attributes.items():
            u.add(v.class_string)
            u.add(v.gen_def_str())

        u.outdent()
        u.blank_line()
        u.indent('def __init__(self, name, parent: Markable, **kwargs):')
        u.add('super().__init__(name, parent)')
        u.add('ft = self.__class__.Field')
        for k, v in self.attributes.items():
            u.add(v.gen_init_str(direct_assign=False))

        u.add('')
        return u
Esempio n. 22
0
    def resolver_string(self):
        if not self.is_alias_key:
            return None
        if self.is_range:
            # 子テーブル且つレンジキーの場合はエイリアスキーとなる
            l = len(self.parent.tag_name) + len(TAG_SEPARATOR)
            parent = self.parent.parent_table
            parent_rk_name = parent.range_key.name

            body = IndentString()

            # getter
            body.add('@property')
            body.indent(
                f'def {self.name}(self) -> {self.python_value_type_str}:')
            body.indent(f'if self.{parent_rk_name}:')
            body.add(
                f'd = self.Meta.key_alias_type.get_data(self.{parent_rk_name}[{l}:])'
            )
            body.outdent()
            body.indent('else:')
            body.add('d = self.Meta.key_alias_type.get_data(None)')
            body.outdent()
            body.add('d.parent = self')
            body.add('return d')
            body.outdent()

            body.blank_line()

            # setter
            body.add(f'@{self.name}.setter')
            body.indent(f'def {self.name}(self, val):')
            body.indent('if val is None:')
            body.add('return')
            body.outdent()
            body.indent('if val.is_empty():')
            body.add('return')
            body.outdent()
            body.add(
                f'self.{parent_rk_name} = f"{self.parent.tag_name}{TAG_SEPARATOR}{{val}}"'
            )
            body.outdent()

            return body
        return None
Esempio n. 23
0
    def class_string(self):
        u = IndentString(
            f'class {snake_to_camel(self.name)}Field(field.MasterKeysField):')

        u.indent('class Value(field.MasterKeysField.Value):')

        acce = IndentString()
        excep = IndentString()
        opt_strings = []

        con_body = IndentString()
        for idx, t in enumerate(self.targets):
            acce.add('@property')
            acce.indent(f'def t{idx}(self):')
            c = self.get_target_table_class_name(idx)

            if self.is_enum(t):
                acce.add(
                    f'return {c}(int(self.label_list[{idx}])) if self.label_list[{idx}] else None'
                )
            else:
                acce.add(f'return self.label_list[{idx}]')
            acce.outdent('')

            if self.is_master(t):
                acce.indent(f'def resolved_t{idx}(self):')
                acce.add(f'return {c}.get_by_cursor(self.t{idx})')
                acce.outdent('')
            elif self.is_enum(t):
                # enumにリゾルバは存在しない
                pass
            else:
                acce.indent(f'async def resolved_t{idx}(self):')
                acce.add(f'return await {c}.query_by_cursor(self.t{idx})')
                acce.outdent('')

            excep.indent(f'if not isinstance(t{idx}, {c}):')
            excep.add(
                f'raise Exception(f"not [{c}] given {{type(t{idx}).__name__}}")'
            )
            excep.outdent()
            opt_strings.append(f't{idx}: {c}')

            if self.is_enum(t):
                con_body.add(f'self.label_list[{idx}] = str(t{idx}.value)')
            else:
                con_body.add(f'self.label_list[{idx}] = t{idx}.one_cursor')

        if not self.parent.is_alone:
            con_body.add('self.update_key()')

        con_head = IndentString(
            f'def connect(self, {", ".join(opt_strings)}):')
        con_head.add(excep)
        con_head.add(con_body)

        u.add(acce, con_head)

        return u
Esempio n. 24
0
    def render_index(self):
        """
        インデックス情報の出力

        :return: IndexString
        """
        table = self.data
        # 単一か子かによって継承元が変わる
        is_alone = table.is_alone
        if is_alone:
            # 個別
            lsi_class_str = IndentString('class LSIndex:')
            gsi_class_str = IndentString('class GSIndex:')
        else:
            # 子
            pn = table.parent_table.class_name
            lsi_class_str = IndentString(f'class LSIndex({pn}.LSIndex):')
            gsi_class_str = IndentString(f'class GSIndex({pn}.LSIndex):')

        # インデックスは複数件あるのでループ
        for idx in table.indexes:
            opt = {}
            opt['projection_keys'] = idx.get('projection', [])
            # LSI or GSI
            if idx['type'] == 'global':
                # GSIはhashキーとrangeキーとキャパシティユニット
                opt['hash_key'] = idx['hash']
                # インデックス名はgsi__{hash}__{range}
                opt['name'] = f'gsi_{idx["hash"]}'
                if 'range' in idx:
                    opt['range_key'] = idx['range']
                    opt['name'] += '__' + idx['range']
                # キャパシティユニット
                caps = idx.get('capacity_units', {})
                if 'capacity_units' in caps:
                    c = caps['capacity_units']
                    opt['read_cap'] = c['read']
                    opt['write_cap'] = c['write']
                else:
                    opt['read_cap'] = 1
                    opt['write_cap'] = 1
                s = ', '.join((f'{k}={json.dumps(v)}' for k, v in opt.items()))
                gsi_class_str.add(f'{opt["name"]} = GSI({s})')
            else:
                # LSIはrangeキーのみ
                opt['name'] = f'lsi_{idx["range"]}'
                opt['range_key'] = idx['range']
                # 処理の都合上PrimaryのHashキーを便宜上のhashキーとして登録する
                if is_alone:
                    opt['hash_key'] = table.hash_key.name
                else:
                    # 子テーブルの場合はPrimaryキーを親テーブルから引く
                    opt['hash_key'] = table.parent_table.hash_key.name
                s = ', '.join((f'{k}={json.dumps(v)}' for k, v in opt.items()))
                lsi_class_str.add(f'{opt["name"]} = LSI({s})')

        # LSIが一つもない場合はpass
        if lsi_class_str.line_num is 1:
            lsi_class_str.add('pass')

        # GSIが一つもない場合はpass
        if gsi_class_str.line_num is 1:
            gsi_class_str.add('pass')
        body = IndentString()

        body.add(lsi_class_str, gsi_class_str)

        return body
Esempio n. 25
0
    def resolver_string(self):
        if not self.is_alias_key:
            return None
        if self.is_range:
            # 子テーブル且つレンジキーの場合はエイリアスキーとなる
            l = len(self.parent.tag_name) + len(TAG_SEPARATOR)
            parent = self.parent.parent_table
            parent_rk_name = parent.range_key.name

            body = IndentString()

            # getter
            body.add('@property')
            body.indent(
                f'def {self.name}(self) -> def_enum.{self.target_enum_name}:')
            body.add(
                f'return self.Meta.key_alias_type.to(int(self.{parent_rk_name}[{l}:]))'
            )
            body.outdent()
            body.blank_line()
            # setter
            body.add(f'@{self.name}.setter')
            body.indent(f'def {self.name}(self, val):')
            body.indent('if val is None:')
            body.add('return')
            body.outdent()
            body.add(
                f'self.{parent_rk_name} = f"{self.parent.tag_name}{TAG_SEPARATOR}{{val.value}}"'
            )
            body.outdent()
            body.outdent()

            return body
        return None
Esempio n. 26
0
    def render_meta(self):
        """
        Metaクラスの出力

        :return: IndexStringインスタンス
        """
        table = self.data
        # hashキー及びrangeキーを取得
        hk = table.hash_key
        rk = table.range_key

        # 単一か子かによって継承元が変わる
        is_alone = table.is_alone
        if is_alone:
            # 単一テーブルの場合は普通に親から継承
            meta = IndentString('class Meta(SoloHatsudenkiTable.Meta):')
        else:
            # 子テーブルの場合はベースに加え、親テーブルのMetaも継承
            meta = IndentString(f'class Meta(ChildMultiHatsudenkiTable.Meta, {table.parent_table.class_name}.Meta):')

        # 共通属性
        meta.add(f'label = "{table.label}"')
        meta.add(f'is_root = {is_alone}')
        meta.add(f'table_name = "{table.table_name}"')

        # 単一テーブルか否かで処理を分岐
        if is_alone:
            # コレクション名
            meta.add(f'collection_name = "{table.collection_name}"')
            # キー情報
            opt = {
                'hash_key': hk.name
            }
            if rk is not None:
                # rangeキーが存在する場合は追加
                opt['range_key'] = rk.name

            # キャパシティユニット
            cap_unit = table.capacity_units
            opt['read_cap'] = cap_unit['read']
            opt['write_cap'] = cap_unit['write']
            # インデックス
            meta.add(f'primary_index = PrimaryIndex(name=None, {self._render_opt_str(opt)})')
        else:
            # 個別にクラスを出力する必要がある場合
            if rk:
                meta.add(rk.class_string)

            # TAGネーム
            meta.add(f'tag_name = "{table.tag_name}"')
            if rk is not None:
                # aliasキー
                meta.add(f'key_alias_name = "{rk.name}"')
                # aliasキータイプ
                meta.add(f'key_alias_type = {rk.def_python_field_class({})}')
        # 空行
        meta.blank_line()
        return meta
Esempio n. 27
0
    def render_header(self) -> IndentString:
        """
        ヘッダ出力

        :return: IndentString
        """
        # インポートするモジュール群
        d = IndentString()
        l = [
            'from __future__ import annotations',
            'import uuid',
            f'from {self.out_module_name} import masters',
            'from datetime import datetime',
            f'from {self.out_module_name} import def_enum',
            'from hatsudenki.packages import field',
            'from hatsudenki.packages.marked import MarkedObject, Markable, MarkedObjectWithIndex',
            'from hatsudenki.packages.table.index import PrimaryIndex, LSI, GSI',
            'from hatsudenki.packages.table.multi import MultiHatsudenkiTable',
            'from hatsudenki.packages.table.solo import SoloHatsudenkiTable',
            'from hatsudenki.packages.table.child import ChildMultiHatsudenkiTable',
            'from hatsudenki.packages.table.child_solo import ChildSoloHatsudenkiTable',
        ]
        d.add(*l)
        d.blank_line(2)

        d.indent('def table_setup():')
        d.add('from hatsudenki.packages.manager.table import TableManager')
        d.add(
            'print(f"load all tables OK. collections={TableManager.get_collection_num()}  tables={TableManager.get_table_num()}")')
        d.blank_line(2)

        return d
Esempio n. 28
0
    def render(self):
        """
        出力

        :return: IndentString
        """
        table = self.data

        # 継承元の決定
        if table.is_alone:
            # solo or multi
            if table.range_key is not None:
                parent_cls_name = 'MultiHatsudenkiTable'
            else:
                parent_cls_name = 'SoloHatsudenkiTable'
        else:
            # solo or multi
            if table.range_key:
                parent_cls_name = f'{table.parent_table.class_name}, ChildMultiHatsudenkiTable'
            else:
                parent_cls_name = f'{table.parent_table.class_name}, ChildSoloHatsudenkiTable'

        # クラス定義
        cls = IndentString(f'class {table.class_name}({parent_cls_name}):')

        # Metaクラス
        cls.add(self.render_meta())

        cls.blank_line()

        cls.add(self.render_fields())
        cls.blank_line()

        # Index
        cls.add(self.render_index())
        cls.blank_line()
        # init
        cls.add(self.render_init())
        cls.blank_line()
        # resolver
        cls.add(self.render_resolver())

        cls.blank_line()

        return cls
Esempio n. 29
0
    def _records(self):
        u = IndentString()
        hk = self.data.hash_key
        rk = self.data.range_key

        # レコード本体
        if rk:
            t = f'Dictionary<{hk.cs_type_name}, List<{self.record_type}>>'
        else:
            t = f'Dictionary<{hk.cs_type_name}, {self.record_type}>'
        u.add(f'private {t} _records = new {t}();')
        u.add(f'public {t} Records')
        u.indent('{')
        u.add('get')
        u.indent('{')
        u.add('return _records;')
        u.outdent('}')
        u.outdent('}')

        return u
Esempio n. 30
0
    def _enum(self):
        u = IndentString()
        u.indent(f'class Enum{self.data.full_classname}(enum.IntEnum):')
        for v in self.data.values:
            u.add(v.python_str)

        if self.data.is_selector:
            u.blank_line()
            u.add('@classmethod')
            u.indent('def resolve(cls, value: int):')
            u.add('from common import masters')
            for v in self.data.values:
                u.add(v.resolve_name)
            u.outdent()

        # 日本語名を出力します
        u.blank_line()
        u.add('@classmethod')
        u.indent('def reverse(cls, value: int) -> str:')
        for v in self.data.values:
            u.add(
                f'if value == cls.{v.enum_value_name}: return "{v.excel_name}"'
            )
        u.outdent()

        u.blank_line(2)

        return u