-
Notifications
You must be signed in to change notification settings - Fork 0
Develop #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Develop #24
Changes from all commits
67fb959
ff9c0bb
5439192
70f527d
59db9eb
f284408
2d7a9ef
a9799b6
558408c
799366b
98a48bd
8369def
0ce8efa
c85411e
3fe500a
cf24615
726b088
2b084e8
0046f4e
fc12622
44da3cf
a07dcd5
a28edb5
3dabfef
619a3c7
902a97e
625733a
f172f59
ee6a62e
bce30c4
54a24a8
d813832
c3f55f9
cf60d57
a33b879
9cbebb1
e16a6d7
a82f3a3
c004d0b
dc8ba2b
af569a0
7f08d87
b12f662
446383b
dd8ae8f
4e2e29b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| # AI Git Automator: Atomic Commits (Optimized) | ||
|
|
||
| **Goal:** Auto-split independent changes into **well-structured Conventional Commits** with mandatory emojis. | ||
|
|
||
| ## 1. Analysis & Grouping (Mandatory) | ||
|
|
||
| * **Ops:** Run `git status` and `git diff`. | ||
| * **Logic:** Cluster files by **logical concern** (type, scope, or intent). | ||
| * **Constraint:** **MUST SPLIT** commits if changes have different types (e.g., `feat` vs `fix`), different scopes, or can be reverted independently. **Do NOT proceed** without full understanding. | ||
|
|
||
| ## 2. Execution Loop | ||
|
|
||
| *Repeat until worktree clean:* | ||
|
|
||
| 1. **Stage:** `git add <paths>` (Select **ONE** coherent concern only). | ||
| 2. **Commit:** Execute the following command immediately (Verify atomicity internally): | ||
| ```bash | ||
| git commit -m "<emoji> <type>(<scope>): <summary> | ||
|
|
||
| Why: | ||
| - [Briefly explain the underlying reason/problem] | ||
| What: | ||
| - [Summary of technical changes] | ||
| Files: | ||
| - [Key files/dirs, omit trivial]" | ||
|
|
||
| ``` | ||
| ## 3. Final Output (Once Finished) | ||
|
|
||
| After all commits are done: | ||
|
|
||
| Print a summary table or list: [Hash] | [Emoji] [Title] | [Files Changed]. | ||
|
|
||
| ## 4. Standards & Rules | ||
|
|
||
| * **Title:** ≤ 72 chars, imperative mood, focus on **WHY**. | ||
| * **Emoji Map:** 🎸feat, 🐛fix, ✏️docs, 💄style, 💡refactor, ⚡️perf, 💍test, 🎡ci, 🤖chore. | ||
| * **Format:** `<emoji> <type>(<scope>): <summary>` (e.g., `🎸 feat(auth): add google oauth`). | ||
| * **Breaking Change:** Add `!` after type (e.g., `feat!(api): ...`). | ||
| * **Order:** `chore/ci` > `refactor` > `feat` > `fix` > `test` > `docs`. | ||
| * **Safety:** No empty commits; **No config changes**; **No `git push`**. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| "setup-worktree": [ | ||
| "npm install" | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,3 +29,5 @@ go.work.sum | |
| .vscode | ||
|
|
||
| .history | ||
|
|
||
| .cursor | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,18 +19,22 @@ const ( | |
| ) | ||
|
|
||
| const ( | ||
| SelectColumsValidateError = "select columns validate error: %s" | ||
| SelectColumnsTypeError = "select type should be string or string slice" | ||
| OrderByColumnsValidateError = "orderBy columns validate error: [%s] not exist" | ||
| OrderByColumnsTypeError = "orderBy type should be string or string slice" | ||
| GroupByColumnsValidateError = "groupBy columns validate error: %s" | ||
| GroupByColumnsTypeError = "groupBy type should be string or string slice" | ||
| CreateDataTypeError = "create data type is wrong, should not be [%s]" | ||
| DataEmptyError = "data is empty" | ||
| UpdateColumnNotExistError = "update column [%s] not exist" | ||
| ColumnNotExistError = "column [%s] not exist" | ||
| MustBeCalledError = "[%s] must be called after [%s]" | ||
| UnsupportedControllerError = "[%s] not supported for %s" | ||
| ModelTypeNotStructError = "model must be a pointer to struct" | ||
| ModelTypeNotSliceError = "model must be a pointer to slice" | ||
| SelectColumsValidateError = "select columns validate error: %s" | ||
| SelectColumnsTypeError = "select type should be string or string slice" | ||
| SelectQualifiedAsteriskError = "qualified wildcard select is not supported: %s" | ||
| SelectAliasNotSupportedError = "select alias is not supported for %s, please use %s" | ||
| OrderByColumnsValidateError = "orderBy columns validate error: [%s] not exist" | ||
| OrderByColumnsTypeError = "orderBy type should be string or string slice" | ||
| GroupByColumnsValidateError = "groupBy columns validate error: %s" | ||
| GroupByColumnsTypeError = "groupBy type should be string or string slice" | ||
| CreateDataTypeError = "create data type is wrong, should not be [%s]" | ||
| DataEmptyError = "data is empty" | ||
| UpdateColumnNotExistError = "update column [%s] not exist" | ||
| ColumnNotExistError = "column [%s] not exist" | ||
| MustBeCalledError = "[%s] must be called after [%s]" | ||
| UnsupportedControllerError = "[%s] not supported for %s" | ||
| ) | ||
|
|
||
| type controllerCall struct { | ||
|
|
@@ -172,10 +176,7 @@ func (m *Impl) setError(format string, a ...any) { | |
| } | ||
|
|
||
| func (m *Impl) haveError() error { | ||
| if err := m.qs.Error(); err != nil { | ||
| return err | ||
| } | ||
| return nil | ||
| return m.qs.Error() | ||
| } | ||
|
|
||
| // preCheck checks if any unsupported methods have been called for the given operation. | ||
|
|
@@ -275,7 +276,7 @@ func (m *Impl) Exclude(exclude ...any) Controller { | |
| func (m *Impl) Where(cond string, args ...any) Controller { | ||
| m.setCalled(ctlWhere) | ||
|
|
||
| m.qs.WhereToSQL(cond, args) | ||
| m.qs.WhereToSQL(cond, args...) | ||
|
|
||
| return m | ||
| } | ||
|
|
@@ -292,6 +293,10 @@ func (m *Impl) Select(selects any) Controller { | |
| if sel == "" { | ||
| return m | ||
| } | ||
| if hasQualifiedWildcardSelect(sel) { | ||
| m.setError(SelectQualifiedAsteriskError, sel) | ||
| return m | ||
| } | ||
| m.qs.StrSelectToSQL(sel) | ||
| case []string: | ||
| if len(sel) == 0 { | ||
|
|
@@ -347,7 +352,7 @@ func (m *Impl) OrderBy(orderBy any) Controller { | |
| if len(orderByVal) == 0 { | ||
| return m | ||
| } | ||
| unknownColumns := []string{} | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| var unknownColumns []string | ||
| for _, by := range orderByVal { | ||
| if by == "" { | ||
| continue | ||
|
|
@@ -413,7 +418,7 @@ func (m *Impl) GroupBy(groupBy any) Controller { | |
| // Having adds a HAVING clause to the query. | ||
| func (m *Impl) Having(having string, args ...any) Controller { | ||
| m.setCalled(ctlHaving) | ||
| m.qs.HavingToSQL(having, args) | ||
| m.qs.HavingToSQL(having, args...) | ||
| return m | ||
| } | ||
|
|
||
|
|
@@ -477,7 +482,7 @@ func (m *Impl) Create(data any) (idOrNum int64, err error) { | |
| return m.bulkCreate(d) | ||
| default: | ||
| v := reflect.ValueOf(data) | ||
| if v.Kind() == reflect.Ptr { | ||
| if v.Kind() == reflect.Pointer { | ||
| v = v.Elem() | ||
| } | ||
| if v.Kind() == reflect.Struct { | ||
|
|
@@ -506,6 +511,10 @@ func (m *Impl) Remove() (num int64, err error) { | |
| } | ||
|
|
||
| func (m *Impl) update(data map[string]any) (num int64, err error) { | ||
| if len(data) == 0 { | ||
| return 0, errors.New("update " + DataEmptyError) | ||
| } | ||
|
|
||
| var ( | ||
| args []any | ||
| updateRows []string | ||
|
|
@@ -553,7 +562,7 @@ func (m *Impl) Count() (num int64, err error) { | |
| } | ||
|
|
||
| func (m *Impl) findOne() (result map[string]any, err error) { | ||
| query, args := m.buildQuery(m.fieldRows) | ||
| query, args := m.buildQuery(m.qs.GetSelectSQL()) | ||
| query += " LIMIT 1" | ||
|
|
||
| res := deepCopyModelPtrStructure(m.modelPtr) | ||
|
|
@@ -562,20 +571,29 @@ func (m *Impl) findOne() (result map[string]any, err error) { | |
|
|
||
| switch { | ||
| case err == nil: | ||
| return modelStruct2Map(res, m.operator.GetDBTag()), nil | ||
| result = modelStruct2Map(res, m.operator.GetDBTag()) | ||
| case errors.Is(err, ErrNotFound): | ||
| return map[string]any{}, nil | ||
| default: | ||
| return map[string]any{}, err | ||
| } | ||
|
|
||
| if m.hasCalled(ctlSelect) { | ||
| result = filterBySelectColumns(result, m.qs.GetSelectSQL()) | ||
| } | ||
|
|
||
| return result, nil | ||
| } | ||
|
|
||
| // FindOne retrieves a single record matching the current query set into a map. | ||
| // It returns the data as a map, or an error if the operation fails. | ||
| func (m *Impl) FindOne() (result map[string]any, err error) { | ||
| if err = m.preCheck("FindOne", ctlSelect, ctlHaving); err != nil { | ||
| if err = m.preCheck("FindOne", ctlHaving); err != nil { | ||
| return result, err | ||
| } | ||
| if m.hasCalled(ctlSelect) && hasSelectAlias(m.qs.GetSelectSQL()) { | ||
| return result, fmt.Errorf(SelectAliasNotSupportedError, "FindOne", "FindOneModel") | ||
| } | ||
|
|
||
| return m.findOne() | ||
| } | ||
|
|
@@ -588,8 +606,8 @@ func (m *Impl) FindOneModel(modelPtr any) (err error) { | |
| } | ||
|
|
||
| rv := reflect.ValueOf(modelPtr) | ||
| if rv.Kind() != reflect.Ptr || rv.Elem().Kind() != reflect.Struct { | ||
| return fmt.Errorf("model must be a pointer to struct") | ||
| if rv.Kind() != reflect.Pointer || rv.Elem().Kind() != reflect.Struct { | ||
| return fmt.Errorf(ModelTypeNotStructError) | ||
| } | ||
|
|
||
| query, args := m.buildQuery(m.qs.GetSelectSQL()) | ||
|
|
@@ -601,25 +619,33 @@ func (m *Impl) FindOneModel(modelPtr any) (err error) { | |
| // FindAll retrieves all records matching the current query set into a slice of maps. | ||
| // It returns the data as a slice of maps, or an error if the operation fails. | ||
| func (m *Impl) FindAll() (result []map[string]any, err error) { | ||
| if err = m.preCheck("FindAll", ctlSelect, ctlHaving); err != nil { | ||
| if err = m.preCheck("FindAll", ctlHaving); err != nil { | ||
| return result, err | ||
| } | ||
| if m.hasCalled(ctlSelect) && hasSelectAlias(m.qs.GetSelectSQL()) { | ||
| return result, fmt.Errorf(SelectAliasNotSupportedError, "FindAll", "FindAllModel") | ||
| } | ||
|
|
||
| query, args := m.buildQuery(m.fieldRows) | ||
| query, args := m.buildQuery(m.qs.GetSelectSQL()) | ||
| query += m.qs.GetLimitSQL() | ||
|
|
||
| res := deepCopyModelPtrStructure(m.modelSlicePtr) | ||
|
|
||
| err = m.operator.FindAll(m.ctx(), res, query, args...) | ||
|
|
||
| switch { | ||
| case err == nil: | ||
| return modelStructSlice2MapSlice(res, m.operator.GetDBTag()), nil | ||
| case errors.Is(err, ErrNotFound): | ||
| return []map[string]any{}, nil | ||
| default: | ||
| if err != nil { | ||
| return []map[string]any{}, err | ||
| } | ||
|
|
||
| result = modelStructSlice2MapSlice(res, m.operator.GetDBTag()) | ||
|
|
||
| if m.hasCalled(ctlSelect) { | ||
| for i, row := range result { | ||
| result[i] = filterBySelectColumns(row, m.qs.GetSelectSQL()) | ||
| } | ||
| } | ||
|
|
||
| return result, nil | ||
| } | ||
|
|
||
| // FindAllModel retrieves all records matching the current query set into a slice of models. | ||
|
|
@@ -630,36 +656,26 @@ func (m *Impl) FindAllModel(modelSlicePtr any) (err error) { | |
| } | ||
|
|
||
| rv := reflect.ValueOf(modelSlicePtr) | ||
| if rv.Kind() != reflect.Ptr || rv.Elem().Kind() != reflect.Slice { | ||
| return fmt.Errorf("model must be a pointer to slice") | ||
| if rv.Kind() != reflect.Pointer || rv.Elem().Kind() != reflect.Slice { | ||
| return fmt.Errorf(ModelTypeNotSliceError) | ||
| } | ||
|
|
||
| query, args := m.buildQuery(m.qs.GetSelectSQL()) | ||
| query += m.qs.GetLimitSQL() | ||
|
|
||
| err = m.operator.FindAll(m.ctx(), modelSlicePtr, query, args...) | ||
|
|
||
| switch { | ||
| case err == nil: | ||
| return nil | ||
| case reflect.ValueOf(modelSlicePtr).Elem().Len() == 0: | ||
| return ErrNotFound | ||
|
cursor[bot] marked this conversation as resolved.
cursor[bot] marked this conversation as resolved.
|
||
| default: | ||
| return err | ||
| } | ||
| return err | ||
| } | ||
|
|
||
| // Delete marks the records as deleted by setting the 'is_deleted' field to true. | ||
| // It returns the number of records marked as deleted. | ||
| // Note: This method is not a true delete operation; it only marks records as deleted. | ||
| func (m *Impl) Delete() (num int64, err error) { | ||
| if err = m.preCheck("Delete", ctlGroupBy, ctlSelect, ctlOrderBy); err != nil { | ||
| if err = m.preCheck("Delete", ctlSelect, ctlGroupBy, ctlHaving); err != nil { | ||
| return 0, err | ||
| } | ||
|
|
||
| data := map[string]any{"is_deleted": true} | ||
|
|
||
| return m.Update(data) | ||
| return m.update(map[string]any{"is_deleted": true}) | ||
|
cursor[bot] marked this conversation as resolved.
|
||
| } | ||
|
|
||
| func (m *Impl) exist() (exist bool, err error) { | ||
|
|
@@ -680,7 +696,7 @@ func (m *Impl) Exist() (exist bool, err error) { | |
| // List retrieves the total count and all data matching the current query set. | ||
| // It returns the total count, data as a slice of maps, and any error encountered. | ||
| func (m *Impl) List() (total int64, data []map[string]any, err error) { | ||
| if err = m.preCheck("List", ctlSelect, ctlHaving); err != nil { | ||
| if err = m.preCheck("List", ctlHaving); err != nil { | ||
| return 0, data, err | ||
| } | ||
|
|
||
|
|
@@ -719,14 +735,16 @@ func (m *Impl) CreateOrUpdate(data map[string]any) (created bool, numOrID int64, | |
| return false, 0, err | ||
| } | ||
|
|
||
| if exist, err := m.exist(); err != nil { | ||
| exist, err := m.exist() | ||
| if err != nil { | ||
| return false, 0, err | ||
| } else if exist { | ||
| if num, err := m.update(data); err != nil { | ||
| } | ||
| if exist { | ||
| num, err := m.update(data) | ||
| if err != nil { | ||
| return false, 0, err | ||
| } else { | ||
| return false, num, nil | ||
| } | ||
| return false, num, nil | ||
| } | ||
|
|
||
| m.reset() | ||
|
|
||


Uh oh!
There was an error while loading. Please reload this page.