storm-cli 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
src/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ # storm-cli — API Starter Kit
2
+ # Core package: declarative schema → full-stack API code generation
src/ast.py ADDED
@@ -0,0 +1,100 @@
1
+ import enum
2
+
3
+ from src.error_handler import raise_error
4
+
5
+
6
+ class AstType(enum.Enum):
7
+ IDENTIFIER = "identifier"
8
+ INT_LITERAL = "int_literal"
9
+ NUM_LITERAL = "num_literal"
10
+ STR_LITERAL = "str_literal"
11
+ BOOL_LITERAL = "bool_literal"
12
+ UNARY_NOT = "unary_not"
13
+ UNARY_BITWISE_NOT = "unary_bitwise_not"
14
+ UNARY_PLUS = "unary_plus"
15
+ UNARY_MINUS = "unary_minus"
16
+ BINARY_MUL = "binary_mul"
17
+ BINARY_DIV = "binary_div"
18
+ BINARY_MOD = "binary_mod"
19
+ BINARY_ADD = "binary_add"
20
+ BINARY_SUB = "binary_sub"
21
+ BINARY_SHL = "binary_shl"
22
+ BINARY_SHR = "binary_shr"
23
+ BINARY_LT = "binary_lt"
24
+ BINARY_LTE = "binary_lte"
25
+ BINARY_GT = "binary_gt"
26
+ BINARY_GTE = "binary_gte"
27
+ BINARY_EQ = "binary_eq"
28
+ BINARY_NE = "binary_ne"
29
+ BINARY_BITWISE_AND = "binary_bitwise_and"
30
+ BINARY_BITWISE_XOR = "binary_bitwise_xor"
31
+ BINARY_BITWISE_OR = "binary_bitwise_or"
32
+ BINARY_LOGICAL_AND = "binary_logical_and"
33
+ BINARY_LOGICAL_OR = "binary_logical_or"
34
+ PROGRAM = "program"
35
+ ENUM_DECL = "enum_decl"
36
+ ENUM_ITEM = "enum_item"
37
+ TABLE_DECL = "table_decl"
38
+ FIELD_DECL = "field_decl"
39
+ TYPE = "type"
40
+ FIELD_ATTRS = "field_attrs"
41
+ FIELD_ATTR = "field_attr"
42
+
43
+
44
+ class ASTNode:
45
+ def __init__(self, node_type, position):
46
+ self.node_type = node_type
47
+ self.position = position
48
+ self.value: str = ""
49
+ self.a = None
50
+ self.b = None
51
+ self.c = None
52
+ self.d = None
53
+ self.next = None
54
+
55
+ @staticmethod
56
+ def create_terminal_node(type: AstType, value: str, position):
57
+ node = ASTNode(type, position)
58
+ node.value = value
59
+ return node
60
+
61
+ @staticmethod
62
+ def create_program(position):
63
+ return ASTNode(AstType.PROGRAM, position)
64
+
65
+ @staticmethod
66
+ def create_enum_decl(position):
67
+ return ASTNode(AstType.ENUM_DECL, position)
68
+
69
+ @staticmethod
70
+ def create_enum_item(position):
71
+ return ASTNode(AstType.ENUM_ITEM, position)
72
+
73
+ @staticmethod
74
+ def create_table_decl(position):
75
+ return ASTNode(AstType.TABLE_DECL, position)
76
+
77
+ @staticmethod
78
+ def create_field_decl(position):
79
+ return ASTNode(AstType.FIELD_DECL, position)
80
+
81
+ @staticmethod
82
+ def create_field_attrs(position):
83
+ return ASTNode(AstType.FIELD_ATTRS, position)
84
+
85
+ @staticmethod
86
+ def create_field_attr(position):
87
+ return ASTNode(AstType.FIELD_ATTR, position)
88
+
89
+ @staticmethod
90
+ def create_binary(op_type: AstType, left, right, position):
91
+ node = ASTNode(op_type, position)
92
+ node.a = left
93
+ node.b = right
94
+ return node
95
+
96
+ @staticmethod
97
+ def create_unary(op_type: AstType, operand, position):
98
+ node = ASTNode(op_type, position)
99
+ node.a = operand
100
+ return node
src/column.py ADDED
@@ -0,0 +1,56 @@
1
+
2
+
3
+
4
+ PRIMITIVE_TYPES = {'int', 'long', 'float', 'double', 'string', 'bool', 'uuid', 'datetime'}
5
+
6
+
7
+ class ColumnType:
8
+ def __init__(self, name: str, attrs=None, is_nullable=False, default_value=None):
9
+ self.name = name
10
+ self.is_nullable = is_nullable
11
+ self.attributes = attrs or {}
12
+ self.is_fk = False
13
+ self.ref_table = None
14
+ self.default_value = default_value
15
+ self.default_value_node = None
16
+
17
+ def to_csharp(self):
18
+ raise Exception("override")
19
+
20
+ def to_php(self):
21
+ raise Exception("override")
22
+
23
+ @classmethod
24
+ def from_ast(cls, type_node, table_names=None):
25
+ table_names = table_names or set()
26
+ type_name = type_node.value
27
+ attrs_node = type_node.a
28
+
29
+ attrs = {}
30
+ if attrs_node:
31
+ cur = attrs_node.a
32
+ while cur:
33
+ val = cur.b.value
34
+ try:
35
+ val = int(val)
36
+ except ValueError:
37
+ pass
38
+ attrs[cur.a.value] = val
39
+ cur = cur.next
40
+
41
+ is_nullable = type_name.endswith('?')
42
+ base_name = type_name[:-1] if is_nullable else type_name
43
+
44
+ if base_name in PRIMITIVE_TYPES:
45
+ return ColumnType(base_name, attrs, is_nullable)
46
+
47
+ col = cls(base_name, attrs, is_nullable)
48
+ if base_name in table_names:
49
+ col.is_fk = True
50
+ col.ref_table = base_name
51
+ return col
52
+
53
+
54
+ class Int(ColumnType):
55
+ def __init__(self, min=None, max=None):
56
+ super().__init__("int", {"min": min or -2147483648, "max": max or 2147483647})
src/enum.py ADDED
@@ -0,0 +1,21 @@
1
+
2
+
3
+
4
+
5
+ class Enum:
6
+ def __init__(self, name, keyValue):
7
+ self.name = name
8
+ self.keyValue = keyValue
9
+
10
+ @classmethod
11
+ def from_ast(cls, node):
12
+ name = node.a.value
13
+ items = []
14
+ cur = node.b
15
+ while cur:
16
+ value = cur.b.value if cur.b else None
17
+ items.append((cur.a.value, value))
18
+ cur = cur.next
19
+ return cls(name, items)
20
+
21
+
src/error_handler.py ADDED
@@ -0,0 +1,35 @@
1
+ import sys
2
+
3
+
4
+ def raise_error(file_path, file_data, message, pos):
5
+ PADDING = 4
6
+ lines = file_data.splitlines()
7
+ line_idx = pos.line - 1
8
+ col = pos.column - 1
9
+
10
+ buf = []
11
+ buf.append(f"Error: {message}")
12
+ buf.append(f" --> {file_path}:{pos.line}:{pos.column}")
13
+ buf.append("")
14
+
15
+ if 0 <= line_idx < len(lines):
16
+ context_before = 2
17
+ context_after = 2
18
+ start = max(0, line_idx - context_before)
19
+ end = min(len(lines), line_idx + context_after + 1)
20
+
21
+ for i in range(start, end):
22
+ line_num = i + 1
23
+ buf.append(f"{line_num:>{PADDING}} | {lines[i]}")
24
+
25
+ if i == line_idx:
26
+ indent = " " * (PADDING + 3)
27
+ col_clamped = max(0, min(col, len(lines[i])))
28
+ pointer = " " * col_clamped + "^"
29
+ remaining = len(lines[i]) - col_clamped
30
+ if remaining > 1:
31
+ pointer += "~" * min(remaining - 1, 5)
32
+ buf.append(f"{indent}{pointer}")
33
+
34
+ sys.stdout.write("\n".join(buf) + "\n")
35
+ sys.exit(1)
@@ -0,0 +1,106 @@
1
+
2
+
3
+
4
+ GENERIC_CONTROLLER_CSHARP = """\
5
+ using System.Threading.Tasks;
6
+ using Microsoft.AspNetCore.Mvc;
7
+ using $$config_iservice_path$$;
8
+ using $$config_dto_path$$;
9
+ using $$config_mapper_path$$;
10
+ using $$config_pagination_path$$;
11
+
12
+ namespace $$config_controller_path$$;
13
+
14
+ [ApiController]
15
+ [Route("api/[controller]")]
16
+ public class GenericController<TEntity, TDto, TRequestDto, TKey> : ControllerBase
17
+ where TEntity : class
18
+ where TDto : class
19
+ where TRequestDto : class
20
+ {
21
+ protected readonly IGenericService<TEntity, TDto, TRequestDto, TKey> _service;
22
+
23
+ public GenericController(IGenericService<TEntity, TDto, TRequestDto, TKey> service)
24
+ {
25
+ _service = service;
26
+ }
27
+ }
28
+ """
29
+
30
+ GENERIC_CONTROLLER_TEMPLATE_CSHARP = """\
31
+ using System.Threading.Tasks;
32
+ using Microsoft.AspNetCore.Mvc;
33
+ using $$config_iservice_path$$;
34
+ using $$config_dto_path$$;
35
+ using $$config_mapper_path$$;
36
+ using $$config_pagination_path$$;
37
+
38
+ namespace $$config_controller_path$$;
39
+
40
+ [ApiController]
41
+ [Route("api/[controller]")]
42
+ public class GenericController<TEntity, TDto, TKey> : GenericController<$Entity$, $TDto$, $TRequestDto$, $TKey$>
43
+ where TEntity : class
44
+ where TDto : class
45
+ {
46
+ [HttpGet("{id}", Name = "Get$Entity$ById")]
47
+ [Tags("$Entity$")]
48
+ [EndpointSummary("Retrieve by id")]
49
+ [EndpointDescription("Returns a single record by its unique identifier")]
50
+ [ProducesResponseType(typeof($TDto$), StatusCodes.Status200OK)]
51
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
52
+ public virtual async Task<ActionResult<$TDto$>> Show([FromRoute] $TKey$ id)
53
+ {
54
+ var result = await _service.GetByIdAsync(id);
55
+ return Ok(result);
56
+ }
57
+
58
+ [HttpGet(Name = "Get$Entity$Paginated")]
59
+ [Tags("$Entity$")]
60
+ [EndpointSummary("Paginated list")]
61
+ [EndpointDescription("Returns a paginated list of records")]
62
+ [ProducesResponseType(typeof(PaginatedResult<$TDto$>), StatusCodes.Status200OK)]
63
+ public virtual async Task<ActionResult<PaginatedResult<$TDto$>>> Index([FromQuery] PaginateQuery query)
64
+ {
65
+ var result = await _service.PaginateAsync(query);
66
+ return Ok(result);
67
+ }
68
+
69
+ [HttpPost(Name = "Create$Entity$")]
70
+ [Tags("$Entity$")]
71
+ [EndpointSummary("Create new")]
72
+ [EndpointDescription("Creates a new record from the provided payload")]
73
+ [ProducesResponseType(typeof($TDto$), StatusCodes.Status200OK)]
74
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
75
+ public virtual async Task<ActionResult<$TDto$>> Store([FromBody] $TRequestDto$ item)
76
+ {
77
+ var result = await _service.CreateAsync(item);
78
+ return Ok(result);
79
+ }
80
+
81
+ [HttpPut("{id}", Name = "Update$Entity$")]
82
+ [Tags("$Entity$")]
83
+ [EndpointSummary("Update by id")]
84
+ [EndpointDescription("Updates an existing record identified by its id with the provided payload")]
85
+ [ProducesResponseType(typeof($TDto$), StatusCodes.Status200OK)]
86
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
87
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
88
+ public virtual async Task<ActionResult<$TDto$>> Update([FromRoute] $TKey$ id, [FromBody] $TRequestDto$ item)
89
+ {
90
+ var result = await _service.UpdateAsync(id, item);
91
+ return Ok(result);
92
+ }
93
+
94
+ [HttpDelete("{id}", Name = "Delete$Entity$")]
95
+ [Tags("$Entity$")]
96
+ [EndpointSummary("Delete by id")]
97
+ [EndpointDescription("Deletes a record by its unique identifier")]
98
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
99
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
100
+ public virtual async Task<IActionResult> Destroy([FromRoute] $TKey$ id)
101
+ {
102
+ await _service.DeleteAsync(id);
103
+ return NoContent();
104
+ }
105
+ }
106
+ """
@@ -0,0 +1,35 @@
1
+ GENERIC_MAPPER_CSHARP = """\
2
+ using AutoMapper;
3
+ using $$config_model_path$$;
4
+ using $$config_dto_path$$;
5
+
6
+ namespace $$config_mapper_path$$;
7
+
8
+ public class GenericMappingProfile<TEntity, TDto> : Profile
9
+ where TEntity : class
10
+ where TDto : class
11
+ {
12
+ public GenericMappingProfile()
13
+ {
14
+ CreateMap<TEntity, TDto>().ReverseMap();
15
+ }
16
+ }
17
+ """
18
+
19
+ GENERIC_MAPPER_TEMPLATE_CSHARP = """\
20
+ using AutoMapper;
21
+ using $$config_model_path$$;
22
+ using $$config_dto_path$$;
23
+
24
+ namespace $$config_mapper_path$$;
25
+
26
+ public class $$Entity$$MappingProfile : Profile
27
+ {
28
+ public $$Entity$$MappingProfile()
29
+ {
30
+ CreateMap<$$TRequestDto$$, $$Entity$$>();
31
+ CreateMap<$$Entity$$, $$TResponseDto$$>();
32
+ CreateMap<$$Entity$$, $$TResponseDtoSimplified$$>();
33
+ }
34
+ }
35
+ """
@@ -0,0 +1,44 @@
1
+
2
+
3
+
4
+
5
+ GENERIC_PAGINATION_CSHARP = """\
6
+ using System;
7
+ using System.Collections.Generic;
8
+ using System.Linq;
9
+ using System.Threading.Tasks;
10
+ using Microsoft.EntityFrameworkCore;
11
+
12
+ namespace $$config_pagination_path$$;
13
+
14
+ public class PaginatedResult<T>
15
+ {
16
+ public List<T> Items { get; set; } = new();
17
+ public int TotalCount { get; set; }
18
+ public int Page { get; set; }
19
+ public int Rows { get; set; }
20
+ public int TotalPages => (int)Math.Ceiling((double)TotalCount / Rows);
21
+ public bool HasPreviousPage => Page > 1;
22
+ public bool HasNextPage => Page < TotalPages;
23
+ }
24
+
25
+ public static class PaginationExtensions
26
+ {
27
+ public static async Task<PaginatedResult<T>> PaginateAsync<T>(
28
+ this IQueryable<T> query, int page = 1, int rows = 20)
29
+ {
30
+ var totalCount = await query.CountAsync();
31
+ var items = await query
32
+ .Skip((page - 1) * rows)
33
+ .Take(rows)
34
+ .ToListAsync();
35
+ return new PaginatedResult<T>
36
+ {
37
+ Items = items,
38
+ TotalCount = totalCount,
39
+ Page = page,
40
+ Rows = rows
41
+ };
42
+ }
43
+ }
44
+ """
@@ -0,0 +1,18 @@
1
+
2
+
3
+
4
+
5
+
6
+ GENERIC_QUERY_CSHARP = """\
7
+
8
+ namespace $$config_pagination_path$$;
9
+
10
+ public class PaginateQuery
11
+ {
12
+ public string? Search { get; set; }
13
+
14
+ public int Page { get; set; } = 1;
15
+
16
+ public int Rows { get; set; } = 20;
17
+ }
18
+ """
@@ -0,0 +1,112 @@
1
+
2
+
3
+
4
+ GENERIC_ISERVICE_CSHARP = """\
5
+ using System;
6
+ using System.Collections.Generic;
7
+ using System.Threading.Tasks;
8
+ using $$config_dto_path$$;
9
+ using $$config_pagination_path$$;
10
+
11
+ namespace $$config_iservice_path$$;
12
+
13
+ public interface IGenericService<TEntity, TDto, TRequestDto, TKey>
14
+ where TEntity : class
15
+ where TDto : class
16
+ where TRequestDto : class
17
+ {
18
+ public Task<TDto> GetByIdAsync(TKey id);
19
+ public Task<PaginatedResult<TDto>> PaginateAsync(PaginateQuery query);
20
+ public Task<TDto> CreateAsync(TRequestDto item);
21
+ public Task<TDto> UpdateAsync(TKey id, TRequestDto item);
22
+ public Task DeleteAsync(TKey id);
23
+ }
24
+ """
25
+
26
+
27
+ GENERIC_SERVICE_CSHARP = """\
28
+ using System;
29
+ using System.Collections.Generic;
30
+ using System.Linq;
31
+ using System.Threading.Tasks;
32
+ using AutoMapper;
33
+ using AutoMapper.QueryableExtensions;
34
+ using Microsoft.EntityFrameworkCore;
35
+ using $$config_iservice_path$$;
36
+ using $$config_model_path$$;
37
+ using $$config_dto_path$$;
38
+ using $$config_mapper_path$$;
39
+ using $$config_pagination_path$$;
40
+
41
+ namespace $$config_service_path$$;
42
+
43
+ public class GenericService<TEntity, TDto, TRequestDto, TKey> : IGenericService<TEntity, TDto, TRequestDto, TKey>
44
+ where TEntity : class
45
+ where TDto : class
46
+ where TRequestDto : class
47
+ {
48
+ protected readonly DbContext _context;
49
+ protected readonly DbSet<TEntity> _table;
50
+ protected readonly IMapper _mapper;
51
+
52
+ public GenericService(DbContext context, IMapper mapper)
53
+ {
54
+ _context = context;
55
+ _table = context.Set<TEntity>();
56
+ _mapper = mapper;
57
+ }
58
+
59
+ public virtual async Task<TDto> GetByIdAsync(TKey id)
60
+ {
61
+ var entity = await _table.FindAsync(id);
62
+ if (entity == null)
63
+ throw new KeyNotFoundException($"{typeof(TEntity).Name} with id {id} not found");
64
+ return _mapper.Map<TDto>(entity);
65
+ }
66
+
67
+ public virtual async Task<PaginatedResult<TDto>> PaginateAsync(PaginateQuery query)
68
+ {
69
+ var q = _table.AsQueryable();
70
+ var totalCount = await q.CountAsync();
71
+ var items = await q
72
+ .Skip((query.Page - 1) * query.Rows)
73
+ .Take(query.Rows)
74
+ .ProjectTo<TDto>(_mapper.ConfigurationProvider)
75
+ .ToListAsync();
76
+ return new PaginatedResult<TDto>
77
+ {
78
+ Items = items,
79
+ TotalCount = totalCount,
80
+ Page = query.Page,
81
+ Rows = query.Rows
82
+ };
83
+ }
84
+
85
+ public virtual async Task<TDto> CreateAsync(TRequestDto item)
86
+ {
87
+ var entity = _mapper.Map<TEntity>(item);
88
+ _table.Add(entity);
89
+ await _context.SaveChangesAsync();
90
+ return _mapper.Map<TDto>(entity);
91
+ }
92
+
93
+ public virtual async Task<TDto> UpdateAsync(TKey id, TRequestDto item)
94
+ {
95
+ var entity = await _table.FindAsync(id);
96
+ if (entity == null)
97
+ throw new KeyNotFoundException($"{typeof(TEntity).Name} with id {id} not found");
98
+ _mapper.Map(item, entity);
99
+ await _context.SaveChangesAsync();
100
+ return _mapper.Map<TDto>(entity);
101
+ }
102
+
103
+ public virtual async Task DeleteAsync(TKey id)
104
+ {
105
+ var entity = await _table.FindAsync(id);
106
+ if (entity == null)
107
+ throw new KeyNotFoundException($"{typeof(TEntity).Name} with id {id} not found");
108
+ _table.Remove(entity);
109
+ await _context.SaveChangesAsync();
110
+ }
111
+ }
112
+ """