parent
240eb1e72c
commit
b9541a6be8
@ -1,5 +1,5 @@
|
||||
package go_library
|
||||
|
||||
func Version() string {
|
||||
return "1.0.68"
|
||||
return "1.0.69"
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 65 MiB After Width: | Height: | Size: 63 MiB |
Binary file not shown.
Binary file not shown.
@ -1,2 +0,0 @@
|
||||
# idea
|
||||
.idea
|
@ -1,22 +0,0 @@
|
||||
language: go
|
||||
go:
|
||||
- "1.14"
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
services:
|
||||
- mongodb
|
||||
before_script:
|
||||
- sleep 15 # https://docs.travis-ci.com/user/database-setup/#mongodb-does-not-immediately-accept-connections
|
||||
- echo "replication:" | sudo tee -a /etc/mongod.conf
|
||||
- |-
|
||||
echo " replSetName: \"rs0\"" | sudo tee -a /etc/mongod.conf
|
||||
- sudo service mongod restart
|
||||
- sleep 15
|
||||
- mongo --eval 'rs.initiate()'
|
||||
- sleep 5
|
||||
|
||||
script:
|
||||
- mongod --version
|
||||
- go test -race -coverprofile=coverage.txt -covermode=atomic ./...
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2020 The Qmgo Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
@ -1,83 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package qmgo
|
||||
|
||||
import (
|
||||
"context"
|
||||
opts "github.com/qiniu/qmgo/options"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
)
|
||||
|
||||
// Pipeline define the pipeline for aggregate
|
||||
type Pipeline []bson.D
|
||||
|
||||
// Aggregate is a handle to a aggregate
|
||||
type Aggregate struct {
|
||||
ctx context.Context
|
||||
pipeline interface{}
|
||||
collection *mongo.Collection
|
||||
options []opts.AggregateOptions
|
||||
}
|
||||
|
||||
// All iterates the cursor from aggregate and decodes each document into results.
|
||||
func (a *Aggregate) All(results interface{}) error {
|
||||
opts := options.Aggregate()
|
||||
if len(a.options) > 0 {
|
||||
opts = a.options[0].AggregateOptions
|
||||
}
|
||||
c, err := a.collection.Aggregate(a.ctx, a.pipeline, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.All(a.ctx, results)
|
||||
}
|
||||
|
||||
// One iterates the cursor from aggregate and decodes current document into result.
|
||||
func (a *Aggregate) One(result interface{}) error {
|
||||
opts := options.Aggregate()
|
||||
if len(a.options) > 0 {
|
||||
opts = a.options[0].AggregateOptions
|
||||
}
|
||||
c, err := a.collection.Aggregate(a.ctx, a.pipeline, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cr := Cursor{
|
||||
ctx: a.ctx,
|
||||
cursor: c,
|
||||
err: err,
|
||||
}
|
||||
defer cr.Close()
|
||||
if !cr.Next(result) {
|
||||
return ErrNoSuchDocuments
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Iter return the cursor after aggregate
|
||||
func (a *Aggregate) Iter() CursorI {
|
||||
opts := options.Aggregate()
|
||||
if len(a.options) > 0 {
|
||||
opts = a.options[0].AggregateOptions
|
||||
}
|
||||
c, err := a.collection.Aggregate(a.ctx, a.pipeline, opts)
|
||||
return &Cursor{
|
||||
ctx: a.ctx,
|
||||
cursor: c,
|
||||
err: err,
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package qmgo
|
||||
|
||||
import "go.mongodb.org/mongo-driver/bson"
|
||||
|
||||
// alias mongo drive bson primitives
|
||||
// thus user don't need to import go.mongodb.org/mongo-driver/mongo, it's all in qmgo
|
||||
type (
|
||||
// M is an alias of bson.M
|
||||
M = bson.M
|
||||
// A is an alias of bson.A
|
||||
A = bson.A
|
||||
// D is an alias of bson.D
|
||||
D = bson.D
|
||||
// E is an alias of bson.E
|
||||
E = bson.E
|
||||
)
|
@ -1,185 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package qmgo
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
// BulkResult is the result type returned by Bulk.Run operation.
|
||||
type BulkResult struct {
|
||||
// The number of documents inserted.
|
||||
InsertedCount int64
|
||||
|
||||
// The number of documents matched by filters in update and replace operations.
|
||||
MatchedCount int64
|
||||
|
||||
// The number of documents modified by update and replace operations.
|
||||
ModifiedCount int64
|
||||
|
||||
// The number of documents deleted.
|
||||
DeletedCount int64
|
||||
|
||||
// The number of documents upserted by update and replace operations.
|
||||
UpsertedCount int64
|
||||
|
||||
// A map of operation index to the _id of each upserted document.
|
||||
UpsertedIDs map[int64]interface{}
|
||||
}
|
||||
|
||||
// Bulk is context for batching operations to be sent to database in a single
|
||||
// bulk write.
|
||||
//
|
||||
// Bulk is not safe for concurrent use.
|
||||
//
|
||||
// Notes:
|
||||
//
|
||||
// Individual operations inside a bulk do not trigger middlewares or hooks
|
||||
// at present.
|
||||
//
|
||||
// Different from original mgo, the qmgo implementation of Bulk does not emulate
|
||||
// bulk operations individually on old versions of MongoDB servers that do not
|
||||
// natively support bulk operations.
|
||||
//
|
||||
// Only operations supported by the official driver are exposed, that is why
|
||||
// InsertMany is missing from the methods.
|
||||
type Bulk struct {
|
||||
coll *Collection
|
||||
|
||||
queue []mongo.WriteModel
|
||||
ordered *bool
|
||||
}
|
||||
|
||||
// Bulk returns a new context for preparing bulk execution of operations.
|
||||
func (c *Collection) Bulk() *Bulk {
|
||||
return &Bulk{
|
||||
coll: c,
|
||||
queue: nil,
|
||||
ordered: nil,
|
||||
}
|
||||
}
|
||||
|
||||
// SetOrdered marks the bulk as ordered or unordered.
|
||||
//
|
||||
// If ordered, writes does not continue after one individual write fails.
|
||||
// Default is ordered.
|
||||
func (b *Bulk) SetOrdered(ordered bool) *Bulk {
|
||||
b.ordered = &ordered
|
||||
return b
|
||||
}
|
||||
|
||||
// InsertOne queues an InsertOne operation for bulk execution.
|
||||
func (b *Bulk) InsertOne(doc interface{}) *Bulk {
|
||||
wm := mongo.NewInsertOneModel().SetDocument(doc)
|
||||
b.queue = append(b.queue, wm)
|
||||
return b
|
||||
}
|
||||
|
||||
// Remove queues a Remove operation for bulk execution.
|
||||
func (b *Bulk) Remove(filter interface{}) *Bulk {
|
||||
wm := mongo.NewDeleteOneModel().SetFilter(filter)
|
||||
b.queue = append(b.queue, wm)
|
||||
return b
|
||||
}
|
||||
|
||||
// RemoveId queues a RemoveId operation for bulk execution.
|
||||
func (b *Bulk) RemoveId(id interface{}) *Bulk {
|
||||
b.Remove(bson.M{"_id": id})
|
||||
return b
|
||||
}
|
||||
|
||||
// RemoveAll queues a RemoveAll operation for bulk execution.
|
||||
func (b *Bulk) RemoveAll(filter interface{}) *Bulk {
|
||||
wm := mongo.NewDeleteManyModel().SetFilter(filter)
|
||||
b.queue = append(b.queue, wm)
|
||||
return b
|
||||
}
|
||||
|
||||
// Upsert queues an Upsert operation for bulk execution.
|
||||
// The replacement should be document without operator
|
||||
func (b *Bulk) Upsert(filter interface{}, replacement interface{}) *Bulk {
|
||||
wm := mongo.NewReplaceOneModel().SetFilter(filter).SetReplacement(replacement).SetUpsert(true)
|
||||
b.queue = append(b.queue, wm)
|
||||
return b
|
||||
}
|
||||
|
||||
// UpsertOne queues an UpsertOne operation for bulk execution.
|
||||
// The update should contain operator
|
||||
func (b *Bulk) UpsertOne(filter interface{}, update interface{}) *Bulk {
|
||||
wm := mongo.NewUpdateOneModel().SetFilter(filter).SetUpdate(update).SetUpsert(true)
|
||||
b.queue = append(b.queue, wm)
|
||||
return b
|
||||
}
|
||||
|
||||
// UpsertId queues an UpsertId operation for bulk execution.
|
||||
// The replacement should be document without operator
|
||||
func (b *Bulk) UpsertId(id interface{}, replacement interface{}) *Bulk {
|
||||
b.Upsert(bson.M{"_id": id}, replacement)
|
||||
return b
|
||||
}
|
||||
|
||||
// UpdateOne queues an UpdateOne operation for bulk execution.
|
||||
// The update should contain operator
|
||||
func (b *Bulk) UpdateOne(filter interface{}, update interface{}) *Bulk {
|
||||
wm := mongo.NewUpdateOneModel().SetFilter(filter).SetUpdate(update)
|
||||
b.queue = append(b.queue, wm)
|
||||
return b
|
||||
}
|
||||
|
||||
// UpdateId queues an UpdateId operation for bulk execution.
|
||||
// The update should contain operator
|
||||
func (b *Bulk) UpdateId(id interface{}, update interface{}) *Bulk {
|
||||
b.UpdateOne(bson.M{"_id": id}, update)
|
||||
return b
|
||||
}
|
||||
|
||||
// UpdateAll queues an UpdateAll operation for bulk execution.
|
||||
// The update should contain operator
|
||||
func (b *Bulk) UpdateAll(filter interface{}, update interface{}) *Bulk {
|
||||
wm := mongo.NewUpdateManyModel().SetFilter(filter).SetUpdate(update)
|
||||
b.queue = append(b.queue, wm)
|
||||
return b
|
||||
}
|
||||
|
||||
// Run executes the collected operations in a single bulk operation.
|
||||
//
|
||||
// A successful call resets the Bulk. If an error is returned, the internal
|
||||
// queue of operations is unchanged, containing both successful and failed
|
||||
// operations.
|
||||
func (b *Bulk) Run(ctx context.Context) (*BulkResult, error) {
|
||||
opts := options.BulkWriteOptions{
|
||||
Ordered: b.ordered,
|
||||
}
|
||||
result, err := b.coll.collection.BulkWrite(ctx, b.queue, &opts)
|
||||
if err != nil {
|
||||
// In original mgo, queue is not reset in case of error.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Empty the queue for possible reuse, as per mgo's behavior.
|
||||
b.queue = nil
|
||||
|
||||
return &BulkResult{
|
||||
InsertedCount: result.InsertedCount,
|
||||
MatchedCount: result.MatchedCount,
|
||||
ModifiedCount: result.ModifiedCount,
|
||||
DeletedCount: result.DeletedCount,
|
||||
UpsertedCount: result.UpsertedCount,
|
||||
UpsertedIDs: result.UpsertedIDs,
|
||||
}, nil
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package qmgo
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
)
|
||||
|
||||
// Cursor struct define
|
||||
type Cursor struct {
|
||||
ctx context.Context
|
||||
cursor *mongo.Cursor
|
||||
err error
|
||||
}
|
||||
|
||||
// Next gets the next document for this cursor. It returns true if there were no errors and the cursor has not been
|
||||
// exhausted.
|
||||
func (c *Cursor) Next(result interface{}) bool {
|
||||
if c.err != nil {
|
||||
return false
|
||||
}
|
||||
var err error
|
||||
if c.cursor.Next(c.ctx) {
|
||||
err = c.cursor.Decode(result)
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// All iterates the cursor and decodes each document into results. The results parameter must be a pointer to a slice.
|
||||
// recommend to use All() in struct Query or Aggregate
|
||||
func (c *Cursor) All(results interface{}) error {
|
||||
if c.err != nil {
|
||||
return c.err
|
||||
}
|
||||
return c.cursor.All(c.ctx, results)
|
||||
}
|
||||
|
||||
// ID returns the ID of this cursor, or 0 if the cursor has been closed or exhausted.
|
||||
//func (c *Cursor) ID() int64 {
|
||||
// if c.err != nil {
|
||||
// return 0
|
||||
// }
|
||||
// return c.cursor.ID()
|
||||
//}
|
||||
|
||||
// Close closes this cursor. Next and TryNext must not be called after Close has been called.
|
||||
// When the cursor object is no longer in use, it should be actively closed
|
||||
func (c *Cursor) Close() error {
|
||||
if c.err != nil {
|
||||
return c.err
|
||||
}
|
||||
return c.cursor.Close(c.ctx)
|
||||
}
|
||||
|
||||
// Err return the last error of Cursor, if no error occurs, return nil
|
||||
func (c *Cursor) Err() error {
|
||||
if c.err != nil {
|
||||
return c.err
|
||||
}
|
||||
return c.cursor.Err()
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package qmgo
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
opts "github.com/qiniu/qmgo/options"
|
||||
"go.mongodb.org/mongo-driver/bson/bsoncodec"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
// Database is a handle to a MongoDB database
|
||||
type Database struct {
|
||||
database *mongo.Database
|
||||
|
||||
registry *bsoncodec.Registry
|
||||
}
|
||||
|
||||
// Collection gets collection from database
|
||||
func (d *Database) Collection(name string) *Collection {
|
||||
var cp *mongo.Collection
|
||||
cp = d.database.Collection(name)
|
||||
|
||||
return &Collection{
|
||||
collection: cp,
|
||||
registry: d.registry,
|
||||
}
|
||||
}
|
||||
|
||||
// GetDatabaseName returns the name of database
|
||||
func (d *Database) GetDatabaseName() string {
|
||||
return d.database.Name()
|
||||
}
|
||||
|
||||
// DropDatabase drops database
|
||||
func (d *Database) DropDatabase(ctx context.Context) error {
|
||||
return d.database.Drop(ctx)
|
||||
}
|
||||
|
||||
// RunCommand executes the given command against the database.
|
||||
//
|
||||
// The runCommand parameter must be a document for the command to be executed. It cannot be nil.
|
||||
// This must be an order-preserving type such as bson.D. Map types such as bson.M are not valid.
|
||||
// If the command document contains a session ID or any transaction-specific fields, the behavior is undefined.
|
||||
//
|
||||
// The opts parameter can be used to specify options for this operation (see the options.RunCmdOptions documentation).
|
||||
func (d *Database) RunCommand(ctx context.Context, runCommand interface{}, opts ...opts.RunCommandOptions) *mongo.SingleResult {
|
||||
option := options.RunCmd()
|
||||
if len(opts) > 0 && opts[0].RunCmdOptions != nil {
|
||||
option = opts[0].RunCmdOptions
|
||||
}
|
||||
return d.database.RunCommand(ctx, runCommand, option)
|
||||
}
|
||||
|
||||
// CreateCollection executes a create command to explicitly create a new collection with the specified name on the
|
||||
// server. If the collection being created already exists, this method will return a mongo.CommandError. This method
|
||||
// requires driver version 1.4.0 or higher.
|
||||
//
|
||||
// The opts parameter can be used to specify options for the operation (see the options.CreateCollectionOptions
|
||||
// documentation).
|
||||
func (db *Database) CreateCollection(ctx context.Context, name string, opts ...opts.CreateCollectionOptions) error {
|
||||
var option = make([]*options.CreateCollectionOptions,0,len(opts))
|
||||
for _,opt := range opts{
|
||||
if opt.CreateCollectionOptions != nil{
|
||||
option = append(option,opt.CreateCollectionOptions)
|
||||
}
|
||||
}
|
||||
return db.database.CreateCollection(ctx,name,option...)
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package qmgo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrQueryNotSlicePointer return if result argument is not a pointer to a slice
|
||||
ErrQueryNotSlicePointer = errors.New("result argument must be a pointer to a slice")
|
||||
// ErrQueryNotSliceType return if result argument is not slice address
|
||||
ErrQueryNotSliceType = errors.New("result argument must be a slice address")
|
||||
// ErrQueryResultTypeInconsistent return if result type is not equal mongodb value type
|
||||
ErrQueryResultTypeInconsistent = errors.New("result type is not equal mongodb value type")
|
||||
// ErrQueryResultValCanNotChange return if the value of result can not be changed
|
||||
ErrQueryResultValCanNotChange = errors.New("the value of result can not be changed")
|
||||
// ErrNoSuchDocuments return if no document found
|
||||
ErrNoSuchDocuments = mongo.ErrNoDocuments
|
||||
// ErrTransactionRetry return if transaction need to retry
|
||||
ErrTransactionRetry = errors.New("retry transaction")
|
||||
// ErrTransactionNotSupported return if transaction not supported
|
||||
ErrTransactionNotSupported = errors.New("transaction not supported")
|
||||
// ErrNotSupportedUsername return if username is invalid
|
||||
ErrNotSupportedUsername = errors.New("username not supported")
|
||||
// ErrNotSupportedPassword return if password is invalid
|
||||
ErrNotSupportedPassword = errors.New("password not supported")
|
||||
// ErrNotValidSliceToInsert return if insert argument is not valid slice
|
||||
ErrNotValidSliceToInsert = errors.New("must be valid slice to insert")
|
||||
// ErrReplacementContainUpdateOperators return if replacement document contain update operators
|
||||
ErrReplacementContainUpdateOperators = errors.New("replacement document cannot contain keys beginning with '$'")
|
||||
)
|
||||
|
||||
// IsErrNoDocuments check if err is no documents, both mongo-go-driver error and qmgo custom error
|
||||
// Deprecated, simply call if err == ErrNoSuchDocuments or if err == mongo.ErrNoDocuments
|
||||
func IsErrNoDocuments(err error) bool {
|
||||
if err == ErrNoSuchDocuments {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsDup check if err is mongo E11000 (duplicate err)。
|
||||
func IsDup(err error) bool {
|
||||
return err != nil && strings.Contains(err.Error(), "E11000")
|
||||
}
|
@ -1,147 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package field
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CustomFields defines struct of supported custom fields
|
||||
type CustomFields struct {
|
||||
createAt string
|
||||
updateAt string
|
||||
id string
|
||||
}
|
||||
|
||||
// CustomFieldsHook defines the interface, CustomFields return custom field user want to change
|
||||
type CustomFieldsHook interface {
|
||||
CustomFields() CustomFieldsBuilder
|
||||
}
|
||||
|
||||
// CustomFieldsBuilder defines the interface which user use to set custom fields
|
||||
type CustomFieldsBuilder interface {
|
||||
SetUpdateAt(fieldName string) CustomFieldsBuilder
|
||||
SetCreateAt(fieldName string) CustomFieldsBuilder
|
||||
SetId(fieldName string) CustomFieldsBuilder
|
||||
}
|
||||
|
||||
// NewCustom creates new Builder which is used to set the custom fields
|
||||
func NewCustom() CustomFieldsBuilder {
|
||||
return &CustomFields{}
|
||||
}
|
||||
|
||||
// SetUpdateAt set the custom UpdateAt field
|
||||
func (c *CustomFields) SetUpdateAt(fieldName string) CustomFieldsBuilder {
|
||||
c.updateAt = fieldName
|
||||
return c
|
||||
}
|
||||
|
||||
// SetCreateAt set the custom CreateAt field
|
||||
func (c *CustomFields) SetCreateAt(fieldName string) CustomFieldsBuilder {
|
||||
c.createAt = fieldName
|
||||
return c
|
||||
}
|
||||
|
||||
// SetId set the custom Id field
|
||||
func (c *CustomFields) SetId(fieldName string) CustomFieldsBuilder {
|
||||
c.id = fieldName
|
||||
return c
|
||||
}
|
||||
|
||||
// CustomCreateTime changes the custom create time
|
||||
func (c CustomFields) CustomCreateTime(doc interface{}) {
|
||||
if c.createAt == "" {
|
||||
return
|
||||
}
|
||||
fieldName := c.createAt
|
||||
setTime(doc, fieldName, false)
|
||||
return
|
||||
}
|
||||
|
||||
// CustomUpdateTime changes the custom update time
|
||||
func (c CustomFields) CustomUpdateTime(doc interface{}) {
|
||||
if c.updateAt == "" {
|
||||
return
|
||||
}
|
||||
fieldName := c.updateAt
|
||||
setTime(doc, fieldName, true)
|
||||
return
|
||||
}
|
||||
|
||||
// CustomUpdateTime changes the custom update time
|
||||
func (c CustomFields) CustomId(doc interface{}) {
|
||||
if c.id == "" {
|
||||
return
|
||||
}
|
||||
fieldName := c.id
|
||||
setId(doc, fieldName)
|
||||
return
|
||||
}
|
||||
|
||||
// setTime changes the custom time fields
|
||||
// The overWrite defines if change value when the filed has valid value
|
||||
func setTime(doc interface{}, fieldName string, overWrite bool) {
|
||||
if reflect.Ptr != reflect.TypeOf(doc).Kind() {
|
||||
fmt.Println("not a point type")
|
||||
return
|
||||
}
|
||||
e := reflect.ValueOf(doc).Elem()
|
||||
ca := e.FieldByName(fieldName)
|
||||
if ca.CanSet() {
|
||||
tt := time.Now()
|
||||
switch a := ca.Interface().(type) {
|
||||
case time.Time:
|
||||
if ca.Interface().(time.Time).IsZero() {
|
||||
ca.Set(reflect.ValueOf(tt))
|
||||
} else if overWrite {
|
||||
ca.Set(reflect.ValueOf(tt))
|
||||
}
|
||||
case int64:
|
||||
if ca.Interface().(int64) == 0 {
|
||||
ca.SetInt(tt.Unix())
|
||||
} else if overWrite {
|
||||
ca.SetInt(tt.Unix())
|
||||
}
|
||||
default:
|
||||
fmt.Println("unsupported type to setTime", a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setId changes the custom Id fields
|
||||
func setId(doc interface{}, fieldName string) {
|
||||
if reflect.Ptr != reflect.TypeOf(doc).Kind() {
|
||||
fmt.Println("not a point type")
|
||||
return
|
||||
}
|
||||
e := reflect.ValueOf(doc).Elem()
|
||||
ca := e.FieldByName(fieldName)
|
||||
if ca.CanSet() {
|
||||
switch a := ca.Interface().(type) {
|
||||
case primitive.ObjectID:
|
||||
if ca.Interface().(primitive.ObjectID).IsZero() {
|
||||
ca.Set(reflect.ValueOf(primitive.NewObjectID()))
|
||||
}
|
||||
case string:
|
||||
if ca.String() == "" {
|
||||
ca.SetString(primitive.NewObjectID().Hex())
|
||||
}
|
||||
default:
|
||||
fmt.Println("unsupported type to setId", a)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package field
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
// DefaultFieldHook defines the interface to change default fields by hook
|
||||
type DefaultFieldHook interface {
|
||||
DefaultUpdateAt()
|
||||
DefaultCreateAt()
|
||||
DefaultId()
|
||||
}
|
||||
|
||||
// DefaultField defines the default fields to handle when operation happens
|
||||
// import the DefaultField in document struct to make it working
|
||||
type DefaultField struct {
|
||||
Id primitive.ObjectID `bson:"_id"`
|
||||
CreateAt time.Time `bson:"createAt"`
|
||||
UpdateAt time.Time `bson:"updateAt"`
|
||||
}
|
||||
|
||||
// DefaultUpdateAt changes the default updateAt field
|
||||
func (df *DefaultField) DefaultUpdateAt() {
|
||||
df.UpdateAt = time.Now().Local()
|
||||
}
|
||||
|
||||
// DefaultCreateAt changes the default createAt field
|
||||
func (df *DefaultField) DefaultCreateAt() {
|
||||
if df.CreateAt.IsZero() {
|
||||
df.CreateAt = time.Now().Local()
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultId changes the default _id field
|
||||
func (df *DefaultField) DefaultId() {
|
||||
if df.Id.IsZero() {
|
||||
df.Id = primitive.NewObjectID()
|
||||
}
|
||||
}
|
@ -1,139 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package field
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/qiniu/qmgo/operator"
|
||||
)
|
||||
|
||||
var nilTime time.Time
|
||||
|
||||
// filedHandler defines the relations between field type and handler
|
||||
var fieldHandler = map[operator.OpType]func(doc interface{}) error{
|
||||
operator.BeforeInsert: beforeInsert,
|
||||
operator.BeforeUpdate: beforeUpdate,
|
||||
operator.BeforeReplace: beforeUpdate,
|
||||
operator.BeforeUpsert: beforeUpsert,
|
||||
}
|
||||
|
||||
//func init() {
|
||||
// middleware.Register(Do)
|
||||
//}
|
||||
|
||||
// Do call the specific method to handle field based on fType
|
||||
// Don't use opts here
|
||||
func Do(ctx context.Context, doc interface{}, opType operator.OpType, opts ...interface{}) error {
|
||||
to := reflect.TypeOf(doc)
|
||||
if to == nil {
|
||||
return nil
|
||||
}
|
||||
switch reflect.TypeOf(doc).Kind() {
|
||||
case reflect.Slice:
|
||||
return sliceHandle(doc, opType)
|
||||
case reflect.Ptr:
|
||||
v := reflect.ValueOf(doc).Elem()
|
||||
switch v.Kind() {
|
||||
case reflect.Slice:
|
||||
return sliceHandle(v.Interface(), opType)
|
||||
default:
|
||||
return do(doc, opType)
|
||||
}
|
||||
}
|
||||
//fmt.Println("not support type")
|
||||
return nil
|
||||
}
|
||||
|
||||
// sliceHandle handles the slice docs
|
||||
func sliceHandle(docs interface{}, opType operator.OpType) error {
|
||||
// []interface{}{UserType{}...}
|
||||
if h, ok := docs.([]interface{}); ok {
|
||||
for _, v := range h {
|
||||
if err := do(v, opType); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// []UserType{}
|
||||
s := reflect.ValueOf(docs)
|
||||
for i := 0; i < s.Len(); i++ {
|
||||
if err := do(s.Index(i).Interface(), opType); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// beforeInsert handles field before insert
|
||||
// If value of field createAt is valid in doc, upsert doesn't change it
|
||||
// If value of field id is valid in doc, upsert doesn't change it
|
||||
// Change the value of field updateAt anyway
|
||||
func beforeInsert(doc interface{}) error {
|
||||
if ih, ok := doc.(DefaultFieldHook); ok {
|
||||
ih.DefaultId()
|
||||
ih.DefaultCreateAt()
|
||||
ih.DefaultUpdateAt()
|
||||
}
|
||||
if ih, ok := doc.(CustomFieldsHook); ok {
|
||||
fields := ih.CustomFields()
|
||||
fields.(*CustomFields).CustomId(doc)
|
||||
fields.(*CustomFields).CustomCreateTime(doc)
|
||||
fields.(*CustomFields).CustomUpdateTime(doc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// beforeUpdate handles field before update
|
||||
func beforeUpdate(doc interface{}) error {
|
||||
if ih, ok := doc.(DefaultFieldHook); ok {
|
||||
ih.DefaultUpdateAt()
|
||||
}
|
||||
if ih, ok := doc.(CustomFieldsHook); ok {
|
||||
fields := ih.CustomFields()
|
||||
fields.(*CustomFields).CustomUpdateTime(doc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// beforeUpsert handles field before upsert
|
||||
// If value of field createAt is valid in doc, upsert doesn't change it
|
||||
// If value of field id is valid in doc, upsert doesn't change it
|
||||
// Change the value of field updateAt anyway
|
||||
func beforeUpsert(doc interface{}) error {
|
||||
if ih, ok := doc.(DefaultFieldHook); ok {
|
||||
ih.DefaultId()
|
||||
ih.DefaultCreateAt()
|
||||
ih.DefaultUpdateAt()
|
||||
}
|
||||
if ih, ok := doc.(CustomFieldsHook); ok {
|
||||
fields := ih.CustomFields()
|
||||
fields.(*CustomFields).CustomId(doc)
|
||||
fields.(*CustomFields).CustomCreateTime(doc)
|
||||
fields.(*CustomFields).CustomUpdateTime(doc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// do check if opType is supported and call fieldHandler
|
||||
func do(doc interface{}, opType operator.OpType) error {
|
||||
if f, ok := fieldHandler[opType]; !ok {
|
||||
return nil
|
||||
} else {
|
||||
return f(doc)
|
||||
}
|
||||
}
|
@ -1,218 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package hook
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/qiniu/qmgo/operator"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// hookHandler defines the relations between hook type and handler
|
||||
var hookHandler = map[operator.OpType]func(ctx context.Context, hook interface{}) error{
|
||||
operator.BeforeInsert: beforeInsert,
|
||||
operator.AfterInsert: afterInsert,
|
||||
operator.BeforeUpdate: beforeUpdate,
|
||||
operator.AfterUpdate: afterUpdate,
|
||||
operator.BeforeQuery: beforeQuery,
|
||||
operator.AfterQuery: afterQuery,
|
||||
operator.BeforeRemove: beforeRemove,
|
||||
operator.AfterRemove: afterRemove,
|
||||
operator.BeforeUpsert: beforeUpsert,
|
||||
operator.AfterUpsert: afterUpsert,
|
||||
operator.BeforeReplace: beforeUpdate,
|
||||
operator.AfterReplace: afterUpdate,
|
||||
}
|
||||
|
||||
//
|
||||
//func init() {
|
||||
// middleware.Register(Do)
|
||||
//}
|
||||
|
||||
// Do call the specific method to handle hook based on hType
|
||||
// If opts has valid value, use it instead of original hook
|
||||
func Do(ctx context.Context, hook interface{}, opType operator.OpType, opts ...interface{}) error {
|
||||
if len(opts) > 0 {
|
||||
hook = opts[0]
|
||||
}
|
||||
|
||||
to := reflect.TypeOf(hook)
|
||||
if to == nil {
|
||||
return nil
|
||||
}
|
||||
switch to.Kind() {
|
||||
case reflect.Slice:
|
||||
return sliceHandle(ctx, hook, opType)
|
||||
case reflect.Ptr:
|
||||
v := reflect.ValueOf(hook).Elem()
|
||||
switch v.Kind() {
|
||||
case reflect.Slice:
|
||||
return sliceHandle(ctx, v.Interface(), opType)
|
||||
default:
|
||||
return do(ctx, hook, opType)
|
||||
}
|
||||
default:
|
||||
return do(ctx, hook, opType)
|
||||
}
|
||||
}
|
||||
|
||||
// sliceHandle handles the slice hooks
|
||||
func sliceHandle(ctx context.Context, hook interface{}, opType operator.OpType) error {
|
||||
// []interface{}{UserType{}...}
|
||||
if h, ok := hook.([]interface{}); ok {
|
||||
for _, v := range h {
|
||||
if err := do(ctx, v, opType); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// []UserType{}
|
||||
s := reflect.ValueOf(hook)
|
||||
for i := 0; i < s.Len(); i++ {
|
||||
if err := do(ctx, s.Index(i).Interface(), opType); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BeforeInsertHook InsertHook defines the insert hook interface
|
||||
type BeforeInsertHook interface {
|
||||
BeforeInsert(ctx context.Context) error
|
||||
}
|
||||
type AfterInsertHook interface {
|
||||
AfterInsert(ctx context.Context) error
|
||||
}
|
||||
|
||||
// beforeInsert calls custom BeforeInsert
|
||||
func beforeInsert(ctx context.Context, hook interface{}) error {
|
||||
if ih, ok := hook.(BeforeInsertHook); ok {
|
||||
return ih.BeforeInsert(ctx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// afterInsert calls custom AfterInsert
|
||||
func afterInsert(ctx context.Context, hook interface{}) error {
|
||||
if ih, ok := hook.(AfterInsertHook); ok {
|
||||
return ih.AfterInsert(ctx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BeforeUpdateHook defines the Update hook interface
|
||||
type BeforeUpdateHook interface {
|
||||
BeforeUpdate(ctx context.Context) error
|
||||
}
|
||||
type AfterUpdateHook interface {
|
||||
AfterUpdate(ctx context.Context) error
|
||||
}
|
||||
|
||||
// beforeUpdate calls custom BeforeUpdate
|
||||
func beforeUpdate(ctx context.Context, hook interface{}) error {
|
||||
if ih, ok := hook.(BeforeUpdateHook); ok {
|
||||
return ih.BeforeUpdate(ctx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// afterUpdate calls custom AfterUpdate
|
||||
func afterUpdate(ctx context.Context, hook interface{}) error {
|
||||
if ih, ok := hook.(AfterUpdateHook); ok {
|
||||
return ih.AfterUpdate(ctx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BeforeQueryHook QueryHook defines the query hook interface
|
||||
type BeforeQueryHook interface {
|
||||
BeforeQuery(ctx context.Context) error
|
||||
}
|
||||
type AfterQueryHook interface {
|
||||
AfterQuery(ctx context.Context) error
|
||||
}
|
||||
|
||||
// beforeQuery calls custom BeforeQuery
|
||||
func beforeQuery(ctx context.Context, hook interface{}) error {
|
||||
if ih, ok := hook.(BeforeQueryHook); ok {
|
||||
return ih.BeforeQuery(ctx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// afterQuery calls custom AfterQuery
|
||||
func afterQuery(ctx context.Context, hook interface{}) error {
|
||||
if ih, ok := hook.(AfterQueryHook); ok {
|
||||
return ih.AfterQuery(ctx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BeforeRemoveHook RemoveHook defines the remove hook interface
|
||||
type BeforeRemoveHook interface {
|
||||
BeforeRemove(ctx context.Context) error
|
||||
}
|
||||
type AfterRemoveHook interface {
|
||||
AfterRemove(ctx context.Context) error
|
||||
}
|
||||
|
||||
// beforeRemove calls custom BeforeRemove
|
||||
func beforeRemove(ctx context.Context, hook interface{}) error {
|
||||
if ih, ok := hook.(BeforeRemoveHook); ok {
|
||||
return ih.BeforeRemove(ctx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// afterRemove calls custom AfterRemove
|
||||
func afterRemove(ctx context.Context, hook interface{}) error {
|
||||
if ih, ok := hook.(AfterRemoveHook); ok {
|
||||
return ih.AfterRemove(ctx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BeforeUpsertHook UpsertHook defines the upsert hook interface
|
||||
type BeforeUpsertHook interface {
|
||||
BeforeUpsert(ctx context.Context) error
|
||||
}
|
||||
type AfterUpsertHook interface {
|
||||
AfterUpsert(ctx context.Context) error
|
||||
}
|
||||
|
||||
// beforeUpsert calls custom BeforeUpsert
|
||||
func beforeUpsert(ctx context.Context, hook interface{}) error {
|
||||
if ih, ok := hook.(BeforeUpsertHook); ok {
|
||||
return ih.BeforeUpsert(ctx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// afterUpsert calls custom AfterUpsert
|
||||
func afterUpsert(ctx context.Context, hook interface{}) error {
|
||||
if ih, ok := hook.(AfterUpsertHook); ok {
|
||||
return ih.AfterUpsert(ctx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// do check if opType is supported and call hookHandler
|
||||
func do(ctx context.Context, hook interface{}, opType operator.OpType) error {
|
||||
if f, ok := hookHandler[opType]; !ok {
|
||||
return nil
|
||||
} else {
|
||||
return f(ctx, hook)
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package qmgo
|
||||
|
||||
import "go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
// CollectionI
|
||||
// 集合操作接口
|
||||
//type CollectionI interface {
|
||||
// Find(filter interface{}) QueryI
|
||||
// InsertOne(doc interface{}) (*mongo.InsertOneResult, error)
|
||||
// InsertMany(docs ...interface{}) (*mongo.InsertManyResult, error)
|
||||
// Upsert(filter interface{}, replacement interface{}) (*mongo.UpdateResult, error)
|
||||
// UpdateOne(filter interface{}, update interface{}) error
|
||||
// UpdateAll(filter interface{}, update interface{}) (*mongo.UpdateResult, error)
|
||||
// DeleteOne(filter interface{}) error
|
||||
// RemoveAll(selector interface{}) (*mongo.DeleteResult, error)
|
||||
// EnsureIndex(indexes []string, isUnique bool)
|
||||
// EnsureIndexes(uniques []string, indexes []string)
|
||||
//}
|
||||
|
||||
// Change holds fields for running a findAndModify command via the Query.Apply method.
|
||||
type Change struct {
|
||||
Update interface{} // update/replace document
|
||||
Replace bool // Whether to replace the document rather than updating
|
||||
Remove bool // Whether to remove the document found rather than updating
|
||||
Upsert bool // Whether to insert in case the document isn't found, take effect when Remove is false
|
||||
ReturnNew bool // Should the modified document be returned rather than the old one, take effect when Remove is false
|
||||
}
|
||||
|
||||
// CursorI Cursor interface
|
||||
type CursorI interface {
|
||||
Next(result interface{}) bool
|
||||
Close() error
|
||||
Err() error
|
||||
All(results interface{}) error
|
||||
//ID() int64
|
||||
}
|
||||
|
||||
// QueryI Query interface
|
||||
type QueryI interface {
|
||||
Collation(collation *options.Collation) QueryI
|
||||
Sort(fields ...string) QueryI
|
||||
Select(selector interface{}) QueryI
|
||||
Skip(n int64) QueryI
|
||||
BatchSize(n int64) QueryI
|
||||
NoCursorTimeout(n bool) QueryI
|
||||
Limit(n int64) QueryI
|
||||
One(result interface{}) error
|
||||
All(result interface{}) error
|
||||
Count() (n int64, err error)
|
||||
EstimatedCount() (n int64, err error)
|
||||
Distinct(key string, result interface{}) error
|
||||
Cursor() CursorI
|
||||
Apply(change Change, result interface{}) error
|
||||
Hint(hint interface{}) QueryI
|
||||
}
|
||||
|
||||
// AggregateI define the interface of aggregate
|
||||
type AggregateI interface {
|
||||
All(results interface{}) error
|
||||
One(result interface{}) error
|
||||
Iter() CursorI
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/qiniu/qmgo/field"
|
||||
"github.com/qiniu/qmgo/hook"
|
||||
"github.com/qiniu/qmgo/operator"
|
||||
"github.com/qiniu/qmgo/validator"
|
||||
)
|
||||
|
||||
// callback define the callback function type
|
||||
type callback func(ctx context.Context, doc interface{}, opType operator.OpType, opts ...interface{}) error
|
||||
|
||||
// middlewareCallback the register callback slice
|
||||
// some callbacks initial here without Register() for order
|
||||
var middlewareCallback = []callback{
|
||||
hook.Do,
|
||||
field.Do,
|
||||
validator.Do,
|
||||
}
|
||||
|
||||
// Register register callback into middleware
|
||||
func Register(cb callback) {
|
||||
middlewareCallback = append(middlewareCallback, cb)
|
||||
}
|
||||
|
||||
// Do call every registers
|
||||
// The doc is always the document to operate
|
||||
func Do(ctx context.Context, content interface{}, opType operator.OpType, opts ...interface{}) error {
|
||||
for _, cb := range middlewareCallback {
|
||||
if err := cb(ctx, content, opType, opts...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
||||
|
||||
// Aggregation Pipeline Operators
|
||||
// refer: https://docs.mongodb.com/manual/reference/operator/aggregation/
|
||||
const (
|
||||
// Arithmetic Expression Operators
|
||||
Abs = "$abs"
|
||||
Add = "$add"
|
||||
Ceil = "$ceil"
|
||||
Divide = "$divide"
|
||||
Exp = "$exp"
|
||||
Floor = "$floor"
|
||||
Ln = "$ln"
|
||||
Log = "$log"
|
||||
Log10 = "$log10"
|
||||
Multiply = "$multiply"
|
||||
Pow = "$pow"
|
||||
Round = "$round"
|
||||
Sqrt = "$sqrt"
|
||||
Subtract = "$subtract"
|
||||
Trunc = "$trunc"
|
||||
|
||||
// Array Expression Operators
|
||||
ArrayElemAt = "$arrayElemAt"
|
||||
ArrayToObject = "$arrayToObject"
|
||||
ConcatArrays = "$concatArrays"
|
||||
Filter = "$filter"
|
||||
IndexOfArray = "$indexOfArray"
|
||||
IsArray = "$isArray"
|
||||
Map = "$map"
|
||||
ObjectToArray = "$objectToArray"
|
||||
Range = "$range"
|
||||
Reduce = "$reduce"
|
||||
ReverseArray = "$reverseArray"
|
||||
Zip = "$zip"
|
||||
|
||||
// Comparison Expression Operators
|
||||
Cmp = "$cmp"
|
||||
|
||||
// Conditional Expression Operators
|
||||
Cond = "$cond"
|
||||
IfNull = "$ifNull"
|
||||
Switch = "$switch"
|
||||
|
||||
// Custom Aggregation Expression Operators
|
||||
Accumulator = "$accumulator"
|
||||
Function = "$function"
|
||||
|
||||
// Data Size Operators
|
||||
BinarySize = "$binarySize"
|
||||
BsonSize = "$bsonSize"
|
||||
|
||||
// Date Expression Operators
|
||||
DateFromParts = "$dateFromParts"
|
||||
DateFromString = "$dateFromString"
|
||||
DateToParts = "$dateToParts"
|
||||
DateToString = "$dateToString"
|
||||
DayOfMonth = "$dayOfMonth"
|
||||
DayOfWeek = "$dayOfWeek"
|
||||
DayOfYear = "$dayOfYear"
|
||||
Hour = "$hour"
|
||||
IsoDayOfWeek = "$isoDayOfWeek"
|
||||
IsoWeek = "$isoWeek"
|
||||
IsoWeekYear = "$isoWeekYear"
|
||||
Millisecond = "$millisecond"
|
||||
Minute = "$minute"
|
||||
Month = "$month"
|
||||
Second = "$second"
|
||||
ToDate = "$toDate"
|
||||
Week = "$week"
|
||||
Year = "$year"
|
||||
|
||||
// Literal Expression Operator
|
||||
Literal = "$literal"
|
||||
|
||||
// Object Expression Operators
|
||||
MergeObjects = "$mergeObjects"
|
||||
|
||||
// Set Expression Operators
|
||||
AllElementsTrue = "$allElementsTrue"
|
||||
AnyElementTrue = "$anyElementTrue"
|
||||
SetDifference = "$setDifference"
|
||||
SetEquals = "$setEquals"
|
||||
SetIntersection = "$setIntersection"
|
||||
SetIsSubset = "$setIsSubset"
|
||||
SetUnion = "$setUnion"
|
||||
|
||||
// String Expression Operators
|
||||
Concat = "$concat"
|
||||
IndexOfBytes = "$indexOfBytes"
|
||||
IndexOfCP = "$indexOfCP"
|
||||
Ltrim = "$ltrim"
|
||||
RegexFind = "$regexFind"
|
||||
RegexFindAll = "$regexFindAll"
|
||||
RegexMatch = "$regexMatch"
|
||||
Rtrim = "$rtrim"
|
||||
Split = "$split"
|
||||
StrLenBytes = "$strLenBytes"
|
||||
StrLenCP = "$strLenCP"
|
||||
Strcasecmp = "$strcasecmp"
|
||||
Substr = "$substr"
|
||||
SubstrBytes = "$substrBytes"
|
||||
SubstrCP = "$substrCP"
|
||||
ToLower = "$toLower"
|
||||
ToString = "$toString"
|
||||
Trim = "$trim"
|
||||
ToUpper = "$toUpper"
|
||||
ReplaceOne = "$replaceOne"
|
||||
ReplaceAll = "$replaceAll"
|
||||
|
||||
// Trigonometry Expression Operators
|
||||
Sin = "$sin"
|
||||
Cos = "$cos"
|
||||
Tan = "$tan"
|
||||
Asin = "$asin"
|
||||
Acos = "$acos"
|
||||
Atan = "$atan"
|
||||
Atan2 = "$atan2"
|
||||
Asinh = "$asinh"
|
||||
Acosh = "$acosh"
|
||||
Atanh = "$atanh"
|
||||
DegreesToRadians = "$degreesToRadians"
|
||||
RadiansToDegrees = "$radiansToDegrees"
|
||||
|
||||
// Type Expression Operators
|
||||
Convert = "$convert"
|
||||
ToBool = "$toBool"
|
||||
ToDecimal = "$toDecimal"
|
||||
ToDouble = "$toDouble"
|
||||
ToInt = "$toInt"
|
||||
ToLong = "$toLong"
|
||||
ToObjectID = "$toObjectId"
|
||||
IsNumber = "$isNumber"
|
||||
|
||||
// Accumulators ($group)
|
||||
Avg = "$avg"
|
||||
First = "$first"
|
||||
Last = "$last"
|
||||
|
||||
StdDevPop = "$stdDevPop"
|
||||
StdDevSamp = "$stdDevSamp"
|
||||
Sum = "$sum"
|
||||
|
||||
// Variable Expression Operators
|
||||
Let = "$let"
|
||||
)
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
||||
|
||||
// define the aggregation pipeline stages
|
||||
// refer: https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/
|
||||
const (
|
||||
// Collection Aggregate Stages
|
||||
AddFields = "$addFields"
|
||||
Bucket = "$bucket"
|
||||
BucketAuto = "$bucketAuto"
|
||||
CollStats = "$collStats"
|
||||
Count = "$count"
|
||||
Facet = "$facet"
|
||||
GeoNear = "$geoNear"
|
||||
GraphLookup = "$graphLookup"
|
||||
Group = "$group"
|
||||
IndexStats = "$indexStats"
|
||||
Limit = "$limit"
|
||||
ListSessions = "$listSessions"
|
||||
Lookup = "$lookup"
|
||||
Match = "$match"
|
||||
Merge = "$merge"
|
||||
Out = "$out"
|
||||
PlanCacheStats = "$planCacheStats"
|
||||
Project = "$project"
|
||||
Redact = "$redact"
|
||||
ReplaceRoot = "$replaceRoot"
|
||||
ReplaceWith = "$replaceWith"
|
||||
Sample = "$sample"
|
||||
Skip = "$skip"
|
||||
SortByCount = "$sortByCount"
|
||||
UnionWith = "$unionWith"
|
||||
Unwind = "$unwind"
|
||||
|
||||
// Database Aggregate stages
|
||||
CurrentOp = "$currentOp"
|
||||
ListLocalSessions = "$listLocalSessions"
|
||||
)
|
@ -1,18 +0,0 @@
|
||||
package operator
|
||||
|
||||
type OpType string
|
||||
|
||||
const (
|
||||
BeforeInsert OpType = "beforeInsert"
|
||||
AfterInsert OpType = "afterInsert"
|
||||
BeforeUpdate OpType = "beforeUpdate"
|
||||
AfterUpdate OpType = "afterUpdate"
|
||||
BeforeQuery OpType = "beforeQuery"
|
||||
AfterQuery OpType = "afterQuery"
|
||||
BeforeRemove OpType = "beforeRemove"
|
||||
AfterRemove OpType = "afterRemove"
|
||||
BeforeUpsert OpType = "beforeUpsert"
|
||||
AfterUpsert OpType = "afterUpsert"
|
||||
BeforeReplace OpType = "beforeReplace"
|
||||
AfterReplace OpType = "afterReplace"
|
||||
)
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
||||
|
||||
// define the query and projection operators
|
||||
// refer: https://docs.mongodb.com/manual/reference/operator/query/
|
||||
const (
|
||||
// Comparison
|
||||
Eq = "$eq"
|
||||
Gt = "$gt"
|
||||
Gte = "$gte"
|
||||
In = "$in"
|
||||
Lt = "$lt"
|
||||
Lte = "$lte"
|
||||
Ne = "$ne"
|
||||
Nin = "$nin"
|
||||
|
||||
// Logical
|
||||
And = "$and"
|
||||
Not = "$not"
|
||||
Nor = "$nor"
|
||||
Or = "$or"
|
||||
|
||||
// Element
|
||||
Exists = "$exists"
|
||||
Type = "$type"
|
||||
|
||||
// Evaluation
|
||||
Expr = "$expr"
|
||||
JsonSchema = "$jsonSchema"
|
||||
Mod = "$mod"
|
||||
Regex = "$regex"
|
||||
Text = "$text"
|
||||
Where = "$where"
|
||||
|
||||
// Geo spatial
|
||||
GeoIntersects = "$geoIntersects"
|
||||
GeoWithin = "$geoWithin"
|
||||
Near = "$near"
|
||||
NearSphere = "$nearSphere"
|
||||
|
||||
// Array
|
||||
All = "$all"
|
||||
ElemMatch = "$elemMatch"
|
||||
Size = "$size"
|
||||
|
||||
// Bitwise
|
||||
BitsAllClear = "$bitsAllClear"
|
||||
BitsAllSet = "$bitsAllSet"
|
||||
BitsAnyClear = "$bitsAnyClear"
|
||||
BitsAnySet = "$bitsAnySet"
|
||||
|
||||
// Comments
|
||||
Comment = "$comment"
|
||||
|
||||
// Projection operators
|
||||
Dollar = "$"
|
||||
Meta = "$meta"
|
||||
Slice = "$slice"
|
||||
)
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
||||
|
||||
//Query Modifiers
|
||||
// refer:https://docs.mongodb.com/manual/reference/operator/query-modifier/
|
||||
const (
|
||||
// Modifiers
|
||||
Explain = "$explain"
|
||||
Hint = "$hint"
|
||||
MaxTimeMS = "$maxTimeMS"
|
||||
OrderBy = "$orderby"
|
||||
Query = "$query"
|
||||
ReturnKey = "$returnKey"
|
||||
ShowDiskLoc = "$showDiskLoc"
|
||||
|
||||
// Sort Order
|
||||
Natural = "$natural"
|
||||
)
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
||||
|
||||
// define the update operators
|
||||
// refer: https://docs.mongodb.com/manual/reference/operator/update/
|
||||
const (
|
||||
// Fields
|
||||
CurrentDate = "$currentDate"
|
||||
Inc = "$inc"
|
||||
Min = "$min"
|
||||
Max = "$max"
|
||||
Mul = "$mul"
|
||||
Rename = "$rename"
|
||||
Set = "$set"
|
||||
SetOnInsert = "$setOnInsert"
|
||||
Unset = "$unset"
|
||||
|
||||
// Array Operators
|
||||
AddToSet = "$addToSet"
|
||||
Pop = "$pop"
|
||||
Pull = "$pull"
|
||||
Push = "$push"
|
||||
PullAll = "$pullAll"
|
||||
|
||||
// Array modifiers
|
||||
Each = "$each"
|
||||
Position = "$position"
|
||||
Sort = "$sort"
|
||||
|
||||
// Array bitwise
|
||||
Bit = "$bit"
|
||||
)
|
@ -1,7 +0,0 @@
|
||||
package options
|
||||
|
||||
import "go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
type AggregateOptions struct {
|
||||
*options.AggregateOptions
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package options
|
||||
|
||||
import "go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
type ChangeStreamOptions struct {
|
||||
*options.ChangeStreamOptions
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package options
|
||||
|
||||
import "go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
type ClientOptions struct {
|
||||
*options.ClientOptions
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package options
|
||||
|
||||
import "go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
type CreateCollectionOptions struct {
|
||||
*options.CreateCollectionOptions
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package options
|
||||
|
||||
import "go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
type DatabaseOptions struct {
|
||||
*options.DatabaseOptions
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package options
|
||||
|
||||
import "go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
type IndexModel struct {
|
||||
Key []string // Index key fields; prefix name with dash (-) for descending order
|
||||
*options.IndexOptions
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package options
|
||||
|
||||
import "go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
type InsertOneOptions struct {
|
||||
InsertHook interface{}
|
||||
*options.InsertOneOptions
|
||||
}
|
||||
type InsertManyOptions struct {
|
||||
InsertHook interface{}
|
||||
*options.InsertManyOptions
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package options
|
||||
|
||||
type FindOptions struct {
|
||||
QueryHook interface{}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package options
|
||||
|
||||
import "go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
type RemoveOptions struct {
|
||||
RemoveHook interface{}
|
||||
*options.DeleteOptions
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package options
|
||||
|
||||
import "go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
type ReplaceOptions struct {
|
||||
UpdateHook interface{}
|
||||
*options.ReplaceOptions
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package options
|
||||
|
||||
import "go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
type RunCommandOptions struct {
|
||||
*options.RunCmdOptions
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package options
|
||||
|
||||
import "go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
type SessionOptions struct {
|
||||
*options.SessionOptions
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package options
|
||||
|
||||
import "go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
type TransactionOptions struct {
|
||||
*options.TransactionOptions
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package options
|
||||
|
||||
import "go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
type UpdateOptions struct {
|
||||
UpdateHook interface{}
|
||||
*options.UpdateOptions
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package options
|
||||
|
||||
import "go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
type UpsertOptions struct {
|
||||
UpsertHook interface{}
|
||||
*options.ReplaceOptions
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Qmgo Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package qmgo
|
||||
|
||||
// InsertOneResult is the result type returned by an InsertOne operation.
|
||||
type InsertOneResult struct {
|
||||
// The _id of the inserted document. A value generated by the driver will be of type primitive.ObjectID.
|
||||
InsertedID interface{}
|
||||
}
|
||||
|
||||
// InsertManyResult is a result type returned by an InsertMany operation.
|
||||
type InsertManyResult struct {
|
||||
// The _id values of the inserted documents. Values generated by the driver will be of type primitive.ObjectID.
|
||||
InsertedIDs []interface{}
|
||||
}
|
||||
|
||||
// UpdateResult is the result type returned from UpdateOne, UpdateMany, and ReplaceOne operations.
|
||||
type UpdateResult struct {
|
||||
MatchedCount int64 // The number of documents matched by the filter.
|
||||
ModifiedCount int64 // The number of documents modified by the operation.
|
||||
UpsertedCount int64 // The number of documents upsert by the operation.
|
||||
UpsertedID interface{} // The _id field of the upsert document, or nil if no upsert was done.
|
||||
}
|
||||
|
||||
// DeleteResult is the result type returned by DeleteOne and DeleteMany operations.
|
||||
type DeleteResult struct {
|
||||
DeletedCount int64 // The number of documents deleted.
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/qiniu/qmgo/operator"
|
||||
)
|
||||
|
||||
// use a single instance of Validate, it caches struct info
|
||||
var validate = validator.New()
|
||||
|
||||
// SetValidate let validate can use custom rules
|
||||
func SetValidate(v *validator.Validate) {
|
||||
validate = v
|
||||
}
|
||||
|
||||
// validatorNeeded checks if the validator is needed to opType
|
||||
func validatorNeeded(opType operator.OpType) bool {
|
||||
switch opType {
|
||||
case operator.BeforeInsert, operator.BeforeUpsert, operator.BeforeReplace:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Do calls validator check
|
||||
// Don't use opts here
|
||||
func Do(ctx context.Context, doc interface{}, opType operator.OpType, opts ...interface{}) error {
|
||||
if !validatorNeeded(opType) {
|
||||
return nil
|
||||
}
|
||||
to := reflect.TypeOf(doc)
|
||||
if to == nil {
|
||||
return nil
|
||||
}
|
||||
switch reflect.TypeOf(doc).Kind() {
|
||||
case reflect.Slice:
|
||||
return sliceHandle(doc, opType)
|
||||
case reflect.Ptr:
|
||||
v := reflect.ValueOf(doc).Elem()
|
||||
switch v.Kind() {
|
||||
case reflect.Slice:
|
||||
return sliceHandle(v.Interface(), opType)
|
||||
default:
|
||||
return do(doc)
|
||||
}
|
||||
default:
|
||||
return do(doc)
|
||||
}
|
||||
}
|
||||
|
||||
// sliceHandle handles the slice docs
|
||||
func sliceHandle(docs interface{}, opType operator.OpType) error {
|
||||
// []interface{}{UserType{}...}
|
||||
if h, ok := docs.([]interface{}); ok {
|
||||
for _, v := range h {
|
||||
if err := do(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// []UserType{}
|
||||
s := reflect.ValueOf(docs)
|
||||
for i := 0; i < s.Len(); i++ {
|
||||
if err := do(s.Index(i).Interface()); err != nil {
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// do check if opType is supported and call fieldHandler
|
||||
func do(doc interface{}) error {
|
||||
if !validatorStruct(doc) {
|
||||
return nil
|
||||
}
|
||||
return validate.Struct(doc)
|
||||
}
|
||||
|
||||
// validatorStruct check if kind of doc is validator supported struct
|
||||
// same implement as validator
|
||||
func validatorStruct(doc interface{}) bool {
|
||||
val := reflect.ValueOf(doc)
|
||||
if val.Kind() == reflect.Ptr && !val.IsNil() {
|
||||
val = val.Elem()
|
||||
}
|
||||
if val.Kind() != reflect.Struct || val.Type() == reflect.TypeOf(time.Time{}) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
Loading…
Reference in new issue