精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Go Mongox 開源庫設計分享:簡化 MongoDB 開發的最佳實踐

數據庫 MongoDB
go mongox? 是一個基于泛型的庫,擴展了 MongoDB? 的官方框架。通過泛型技術,它實現了結構體與 MongoDB? 集合的綁定,旨在提供類型安全和簡化的數據操作。

前言

在使用 Go 語言操作 MongoDB 時,Go 開發者的首選庫通常是由 MongoDB 官方團隊推出的 mongo-go-driver。這個庫是專為 Go 語言開發者打造的,支持 MongoDB 的主要功能,并與最新版本的 MongoDB 兼容。通過 mongo-go-driver,Go 開發者可以便捷地連接數據庫,并且能對集合進行查詢、插入、更新、刪除的操作。

盡管 mongo-go-driver 功能強大,但通過進一步封裝,可以在實際開發中顯著提升開發效率,特別是在復雜場景下減少代碼冗余和提升可讀性方面。封裝后,可以有效解決以下常見的問題:

  • 繁瑣的 BSON 數據編寫:構建查詢條件、更新文檔或聚合管道時,往往需要編寫大量 BSON 數據結構。簡單格式的 BSON 數據較易編寫,但面對復雜多層嵌套的文檔時,不僅耗時,還容易出錯。即便是一個小的疏漏,也可能導致結果偏離預期,增加了調試難度。
  • 重復的反序列化代碼:在查詢不同集合的數據時,常常需要編寫重復的反序列化代碼,不僅增加了代碼冗余,也提升了維護成本。
  • 聚合管道操作不夠友好:在進行聚合操作時,缺少對聚合管道的直觀支持。開發者需要手動編寫復雜的 BSON 文檔來定義管道各個階段,這增加了復雜性。

因此,我開發了 go mongox 庫并 針對這些場景進行了優化,利用 Go 語言的泛型特性綁定結構體,同時引入模塊化的 Creator、Updater、Deleter、Finder 和 Aggregator 等功能,分別簡化插入、更新、刪除、查詢和聚合操作。此外,go mongox 還提供了查詢、更新和聚合語句的構建器,以減少代碼冗余,提高開發效率,幫助開發者更專注于業務邏輯的實現。

本文將深入解析 go mongox 開源庫的設計思路與實踐經驗。

準備好了嗎?準備一杯你最喜歡的咖啡或茶,隨著本文一探究竟吧。

倉庫地址:https://github.com/chenmingyong0423/go-mongox

官方文檔:https://go-mongox.dev

go mongox 簡介

go mongox 是一個基于泛型的庫,擴展了 MongoDB 的官方框架。通過泛型技術,它實現了結構體與 MongoDB 集合的綁定,旨在提供類型安全和簡化的數據操作。go mongox 還引入鏈式調用,讓文檔操作更流暢,并且提供了豐富的 BSON 構建器和內置函數,簡化了 BSON 數據的構建。此外,它還支持插件化編程和內置多種鉤子函數,為數據庫操作前后的自定義邏輯提供靈活性,增強了應用的可擴展性和可維護性。

功能特性

  • 泛型的 MongoDB 集合
  • 文檔的 CRUD 操作
  • 聚合操作
  • 內置基本的 Model 結構體,自動化更新默認的 field 字段
  • 支持 BSON 數據的構建
  • 支持結構體 tag 校驗
  • 內置 Hooks
  • 支持插件化編程

泛型的 Collection

為了將結構體與 MongoDB 的集合進行綁定,mongox 定義了一個泛型 Collection 結構體。通過泛型參數 T any,它提供了類型安全的 MongoDB 集合操作,同時保留了對原始 *mongo.Collection 的訪問。

type Collection[T any] struct {
	collection *mongo.Collection
}

func (c *Collection[T]) Collection() *mongo.Collection {
	return c.collection
}

func NewCollection[T any](collection *mongo.Collection) *Collection[T] {
	return &Collection[T]{collection: collection}
}

設計特點與優勢

  • 類型安全

通過泛型,Collection[T] 可以直接操作不同的數據模型類型 T,避免了傳統方法中的類型斷言和轉換,提高了代碼安全性和可讀性。

  • 代碼復用性
  • 泛型支持高度通用的邏輯封裝,使得 CRUD 方法只需實現一次,即可適配所有數據模型類型。這種復用性顯著減少了開發和維護成本。

  • 兼容性

  • Collection() 方法允許用戶直接訪問底層的 *mongo.Collection,保留了原始功能,兼容復雜的 MongoDB 操作需求。

CRUD 操作器

圖片圖片

mongox 內置了五個獨立的操作器類型:Finder、Creator、Updater、Deleter 和 Aggregator,分別負責集合的 查找、創建、更新、刪除 和 聚合 操作。這些操作器實例通過 Collection[T] 對象提供,且每個操作器聚焦于一個具體的集合操作。

func (c *Collection[T]) Finder() *finder.Finder[T] {
	return finder.NewFinder[T](c.collection)
}

func (c *Collection[T]) Creator() *creator.Creator[T] {
	return creator.NewCreator[T](c.collection)
}

func (c *Collection[T]) Updater() *updater.Updater[T] {
	return updater.NewUpdater[T](c.collection)
}

func (c *Collection[T]) Deleter() *deleter.Deleter[T] {
	return deleter.NewDeleter[T](c.collection)
}
func (c *Collection[T]) Aggregator() *aggregator.Aggregator[T] {
	return aggregator.NewAggregator[T](c.collection)
}
// 省略細節代碼

type Finder[T any] struct {}

type Creator[T any] struct {}

type Updater[T any] struct {}

type Deleter[T any] struct {}

type Aggregator[T any] struct {}

設計特點與優勢:

  • 單一職責

每個操作器聚焦于特定的集合操作,符合單一職責原則(SRP)。通過劃分不同的操作器模塊,降低了功能間的耦合度。

  • 擴展性強
  • 每個操作器獨立實現其功能邏輯,便于擴展。例如:如果需要新增批量更新功能,只需擴展 Updater 類型的功能。新增的功能模塊不會影響其他模塊的穩定性。

  • 鏈式調用支持

  • 操作器支持鏈式調用,便于組合復雜的集合操作,讓集合操作的代碼寫起來更加絲滑。

使用示例

  • Finder
user, err := userColl.Finder().
    Filter(query.Id("60e96214a21b1b0001c3d69e")).
    FindOne(context.Background())
  • Creator
insertOneResult, err := userColl.Creator().
    InsertOne(context.Background(), &User{Name: "Mingyong Chen", Age: 18})
  • Updater
updateResult, err := userColl.Updater().
		Filter(query.Id("60e96214a21b1b0001c3d69e")).
		Updates(update.Set("name", "Mingyong Chen")).
		UpdateOne(context.Background())
  • Deleter
deleteResult, err := userColl.Deleter().
    Filter(query.Id("60e96214a21b1b0001c3d69e")).
    DeleteOne(context.Background())
  • Aggregator
// 忽略年齡字段,只查詢名字
users, err := userColl.Aggregator().
    Pipeline(aggregation.NewStageBuilder().Project(bsonx.M("age", 0)).Build()).
    Aggregate(context.Background())

鏈式調用

在設計支持鏈式調用的操作器結構體時,需要明確結構體的職責和需要傳遞的參數。操作器支持鏈式調用的本質是 逐步構建操作所需的參數,最終在調用執行方法時將參數完整地傳遞并執行操作。

以 Updater 為例,它專注于 更新 操作,在這一場景中,鏈式調用的目標是通過連續調用方法來逐步完成以下任務:

  • 設置查詢條件(filter):指定需要更新的文檔范圍。
  • 定義更新內容(updates):明確如何修改文檔的字段。
  • 執行更新操作:將構建好的參數應用到數據庫的更新方法中。

以下是 Updater 的實現:

type Updater[T any] struct {
	collection  *mongo.Collection
	filter      any
	updates     any
}

func (u *Updater[T]) Filter(filter any) *Updater[T] {
	u.filter = filter
	return u
}

func (u *Updater[T]) Updates(updates any) *Updater[T] {
	u.updates = updates
	return u
}

func (u *Updater[T]) UpdateOne(ctx context.Context, opts ...options.Lister[options.UpdateOptions]) (*mongo.UpdateResult, error) {
  // 忽略細節代碼
}

func (u *Updater[T]) UpdateMany(ctx context.Context, opts ...options.Lister[options.UpdateOptions]) (*mongo.UpdateResult, error) {
  // 忽略細節代碼
}

func (u *Updater[T]) Upsert(ctx context.Context, opts ...options.Lister[options.UpdateOptions]) (*mongo.UpdateResult, error) {
  // 忽略細節代碼
}

設計特點與優勢:

  • 簡潔流暢的參數構建

每個鏈式方法負責構建單一的操作參數(如 Filter 構建查詢條件,Updates 構建更新內容),通過鏈式調用逐步完成復雜操作的參數準備,簡化了方法的使用。

  • 符合直覺的調用方式
  • 鏈式調用的代碼邏輯接近自然語言表達。例如:

updateResult, err := userColl.Updater().
		Filter(query.Id("60e96214a21b1b0001c3d69e")).
		Updates(update.Set("name", "Mingyong Chen")).
		UpdateOne(context.Background())
  • 高擴展性與一致性

鏈式方法具有一致的設計風格,新增功能時只需擴展現有鏈式方法,無需改動底層實現。例如,可以輕松為 Updater 增加 Hook 或日志功能。

對于其他操作器,例如 Creator 和 Finder 等,其設計理念也是類似的。

BSON 構建

圖片圖片

mongox 庫提供了強大的 BSON 數據構建功能,幫助開發者簡化與 MongoDB 交互時復雜 BSON 數據的構建。為了解決開發中常見的構建復雜查詢、更新內容以及聚合管道時的繁瑣問題,mongox 將功能劃分為以下幾個包:

  • query 包

專用于構建查詢條件的 BSON 數據。

提供了一系列鏈式構建器和函數,支持條件拼接($and、$or)、范圍查詢($gt、$lt)等復雜查詢。

  • update 模塊
  • 專注于構建更新操作的 BSON 數據,例如 $set、$inc 等。

  • 通過清晰的鏈式操作,幫助開發者快速構建更新內容。

  • aggregation 模塊

  • 專注于構建 MongoDB 的聚合管道(pipeline)。

  • 提供了分步構建復雜聚合管道的工具,支持 $match、$group、$project 等。

  • bsonx 模塊

  • 提供了一系列便捷函數和通用構建器,用于快速構建各種 BSON 數據,覆蓋查詢、更新和聚合之外的常見需求。

query 包

為了支持簡單構建和復雜構建,query 包提供兩種構建模式:直接函數構建和構建器構建。

為了支持簡單查詢語句和復雜查詢語句的構建,query 包提供了兩種靈活的構建模式:直接函數構建 和 構建器構建。這兩種方式的結合滿足了從快速構建到復雜邏輯表達的多種需求。

直接函數構建

通過提供簡單的函數,開發者可以快速構建包含單個操作符的 BSON 查詢條件。這種方式適用于無需組合邏輯的簡單查詢。

func Eq(key string, value any) bson.D {
	return bson.D{bson.E{Key: key, Value: bson.D{{Key: "$eq", Value: value}}}}
}

func Lt(key string, value any) bson.D {
	return bson.D{bson.E{Key: key, Value: bson.D{{Key: "$lt", Value: value}}}}
}

// 忽略其他函數實現

使用示例:

/*
 {
   "name": "陳明勇"
 }
*/
eq := query.Eq("name", "陳明勇")

構建器構建

對于復雜查詢邏輯的構建,mongox 提供了功能強大的 Builder 構建器,通過鏈式調用的方式逐步構建復雜的 BSON 數據。

func NewBuilder() *Builder {
	query := &Builder{
		data: bson.D{},
		err:  make([]error, 0),
	}
	query.comparisonQueryBuilder = comparisonQueryBuilder{parent: query}
	query.logicalQueryBuilder = logicalQueryBuilder{parent: query}
	query.elementQueryBuilder = elementQueryBuilder{parent: query}
	query.arrayQueryBuilder = arrayQueryBuilder{parent: query}
	query.evaluationQueryBuilder = evaluationQueryBuilder{parent: query}
	query.projectionQueryBuilder = projectionQueryBuilder{parent: query}
	return query
}

type Builder struct {
	data bson.D
	comparisonQueryBuilder
	logicalQueryBuilder
	elementQueryBuilder
	arrayQueryBuilder
	evaluationQueryBuilder
	projectionQueryBuilder
}

func (b *Builder) Build() bson.D {
	return b.data
}

構建器的核心是通過組合子構建器(如 comparisonQueryBuilder)實現不同操作符的邏輯。每個子構建器提供其專屬的鏈式方法,Builder 通過組合這些方法形成完整的功能集。

子構建器的實現(示例)

type comparisonQueryBuilder struct {
	parent *Builder
}

func (b *comparisonQueryBuilder) Eq(key string, value any) *Builder {
	e := bson.E{Key: EqOp, Value: value}
	if !b.parent.tryMergeValue(key, e) {
		b.parent.data = append(b.parent.data, bson.E{Key: key, Value: bson.D{e}})
	}
	return b.parent
}

func (b *comparisonQueryBuilder) Gt(key string, value any) *Builder {
	e := bson.E{Key: GtOp, Value: value}
	if !b.parent.tryMergeValue(key, e) {
		b.parent.data = append(b.parent.data, bson.E{Key: key, Value: bson.D{e}})
	}
	return b.parent
}

func (b *comparisonQueryBuilder) Lt(key string, value any) *Builder {
	e := bson.E{Key: LtOp, Value: value}
	if !b.parent.tryMergeValue(key, e) {
		b.parent.data = append(b.parent.data, bson.E{Key: key, Value: bson.D{e}})
	}
	return b.parent
}

構建器主功能:

  • 鏈式調用:開發者可以通過連續調用 Builder 提供的方法來逐步構建查詢條件。
  • 復雜邏輯管理:不同的查詢邏輯(如比較、邏輯、數組操作)由子構建器獨立實現,避免了功能混亂。

使用示例:

/*
      {
          "age": {
              "$gt": {
                  "$numberInt": "18"
              },
              "$lt": {
                  "$numberInt": "30"
              }
          }
      }
  */
query.NewBuilder().Gt("age", 18).Lt("age", 30).Build()

類似于 query 包,mongox 中的其他模塊(如 update、aggregation、bsonx)也采用了類似的設計模式,提供了直接函數構建和構建器構建兩種方式,支持鏈式調用以簡化復雜邏輯的構建。接下來就不對它們多做介紹了。

設計特點與優勢

  • 靈活性:

提供兩種構建模式,分別滿足簡單場景和復雜邏輯場景。

直接函數構建模式適合快速開發,構建器模式支持復雜需求。

  • 職責分離:
  • 不同類型的查詢操作(如比較、邏輯、數組)由獨立的子構建器負責實現,代碼結構清晰,易于擴展。

  • 鏈式調用:

  • 構建器支持鏈式調用,用戶可以直觀地通過方法鏈逐步構建查詢條件,語義清晰,代碼自然流暢。

  • 復用性與擴展性:

  • 新增操作符只需擴展對應子構建器,而無需改動核心邏輯。

  • 不同子構建器之間可獨立維護,降低了代碼的耦合度。

插件化編程

mongox 支持插件化編程,它提供了一種靈活的方式在數據庫操作的前后插入自定義的邏輯,從而增強應用的可擴展性和可維護性。非常適合用于以下場景:

  • 默認字段填充:填充 _id 和創建時間以及更新時間的字段值。
  • 日志記錄:記錄操作前后的信息。
  • 數據驗證:在插入或更新前檢查數據的有效性。
  • 權限校驗:根據業務需求在操作前校驗用戶權限。

核心設計:Callback 結構體

Callback 是 mongox 插件化編程的核心。它通過一系列鉤子屬性(如 beforeInsert、afterInsert 等)將自定義邏輯綁定到集合操作的特定階段。

// 全局回調管理器
var Callbacks = initializeCallbacks()

// 初始化 Callback
func initializeCallbacks() *Callback {
	return &Callback{
		beforeInsert: make([]callbackHandler, 0),
		afterInsert:  make([]callbackHandler, 0),
		beforeUpdate: make([]callbackHandler, 0),
		afterUpdate:  make([]callbackHandler, 0),
		beforeDelete: make([]callbackHandler, 0),
		afterDelete:  make([]callbackHandler, 0),
		beforeUpsert: make([]callbackHandler, 0),
		afterUpsert:  make([]callbackHandler, 0),
		beforeFind:   make([]callbackHandler, 0),
		afterFind:    make([]callbackHandler, 0),
	}
}

type Callback struct {
	beforeInsert []callbackHandler
	afterInsert  []callbackHandler
	beforeUpdate []callbackHandler
	afterUpdate  []callbackHandler
	beforeDelete []callbackHandler
	afterDelete  []callbackHandler
	beforeUpsert []callbackHandler
	afterUpsert  []callbackHandler
	beforeFind   []callbackHandler
	afterFind    []callbackHandler
}

type callbackHandler struct {
	name string
	fn   CbFn
}

type CbFn func(ctx context.Context, opCtx *operation.OpContext, opts ...any) error

// operation_type.go
type OpContext struct {
	Col *mongo.Collection `opt:"-"`
	Doc any
	// filter also can be used as query
	Filter       any
	Updates      any
	Replacement  any
	MongoOptions any
	ModelHook    any
}

func (c *Callback) Execute(ctx context.Context, opCtx *operation.OpContext, opType operation.OpType, opts ...any) error {
	switch opType {
	  // 忽略實現細節,根據操作類型 opType 執行對應的回調函數。
	}
	return nil
}
  • 鉤子類型:

每個集合操作(如插入、更新、查詢等)都有 before 和 after 兩種鉤子。

鉤子以切片形式存儲,支持注冊多個回調函數,這些函數將按順序執行。

  • callbackHandler:
  • name:鉤子函數的名稱,便于管理和調試。

  • fn:具體的回調函數,實現自定義邏輯。

  • 包含兩個屬性:

  • CbFn 回調函數:

  • ctx:上下文,用于控制回調的生命周期。

  • opCtx:操作上下文,包含數據庫操作相關的參數。

  • opts:可選參數,用于傳遞額外信息。

  • 定義了統一的函數簽名,參數包括:

  • 回調執行邏輯

  • 通過 Execute 方法,根據操作類型查找對應的鉤子列表,并按順序執行回調。

  • 如果任何一個回調函數返回錯誤,則中斷執行并返回錯誤信息。

操作上下文:OpContext

OpContext 是回調函數的核心參數,提供了集合操作相關的詳細信息,供開發者在回調函數中靈活使用。

type OpContext struct {
	Col *mongo.Collection `opt:"-"`  // MongoDB 集合實例
	Doc any                          // 文檔
	Filter       any                 // 查詢條件
	Updates      any                 // 更新內容
	Replacement  any                 // 替換內容
	MongoOptions any                 // MongoDB 原生選項
	ModelHook    any                 // 用于判斷綁定的結構體是否實現 Model Hook
}

核心字段說明:

  • Col:當前操作的集合實例。
  • Doc:文檔。
  • Filter:操作的查詢條件,如查找、更新或刪除時使用。
  • Updates:更新內容。
  • Replacement:替換操作的文檔內容。
  • MongoOptions:傳遞 MongoDB 原生的操作選項。
  • ModelHook:與模型相關的自定義上下文,可擴展使用。

使用示例

  • 注冊與刪除回調
// 注冊插件
mongox.RegisterPlugin("after find", func(ctx context.Context, opCtx *operation.OpContext, opts ...any) error {
    if user, ok := opCtx.Doc.(*User); ok {
        fmt.Println(user)
    }
    if users, ok := opCtx.Doc.([]*User); ok {
        fmt.Println(users)
    }
    return nil
}, operation.OpTypeAfterFind)

// 刪除插件
mongox.RemovePlugin("after find", operation.OpTypeAfterFind)
  • 執行回調 在實際的集合操作中,調用 Execute 方法以運行注冊的回調:
err = callback.GetCallback().Execute(ctx, globalOpContext, opType)
if err != nil {
	return
}

設計特點與優勢

  • 靈活性:

每個操作類型支持多個 before 和 after 鉤子,開發者可以自由組合和擴展。可擴展性:

回調以切片形式存儲,允許動態增加、移除或替換鉤子函數。

  • 統一性:
  • 回調函數使用統一簽名,結合 OpContext 提供全面的操作上下文,便于調試和擴展。

  • 解耦性:

  • 集合操作與業務邏輯分離,回調機制將非核心功能獨立實現,保持代碼簡潔和高可維護性。

小結

本文詳細介紹了 go mongox 開源庫的設計思路與實踐經驗,涵蓋了多個核心模塊的設計與實現,包括以下內容:

  • Collection[T] 的設計與實現:類型安全的集合封裝;
  • CRUD 操作器(如 Finder、Creator、Updater、Deleter、Aggregator):模塊化的增刪改查設計;
  • 鏈式調用的實現:簡化復雜操作的流暢調用設計;
  • BSON 數據構建包(query、update、aggregate):高效構建查詢、更新與聚合相關的 BSON 數據;
  • 插件化編程的設計:通過鉤子機制靈活擴展功能。

雖然開發一個功能類似 go mongox 的庫并不復雜,但如何通過精心設計實現出色的擴展性、易用性和復用性,才是開發者需要深思的問題。希望這篇文章能為你提供實用的思路與經驗。

責任編輯:武曉燕 來源: 程序員陳明勇
相關推薦

2024-01-25 08:11:31

2010-11-02 14:11:15

SilverlightWPF微軟開發

2024-08-21 08:02:47

2011-04-06 09:33:40

Push動互聯網

2025-08-28 10:05:00

Go開發

2016-12-27 08:49:55

API設計策略

2022-06-22 06:49:39

Hertz開源HTTP 框架

2014-09-01 09:57:11

Go產品環境最佳語言

2023-05-12 23:31:06

2012-05-24 10:19:42

QQ瀏覽器Android設計分享

2010-12-02 14:32:43

Mobile Web移動互聯網移動Web設計

2012-02-07 09:17:13

2021-10-18 06:54:47

Go開源庫業務

2023-08-31 08:00:00

測試開發

2013-06-13 09:21:31

RESTful APIRESTfulAPI

2016-05-09 09:26:06

架構ios網絡層

2019-11-11 14:15:36

谷歌開源開發

2010-10-28 09:05:42

SilverlightXAML

2011-06-20 06:22:18

ibmdwDB2

2025-10-09 01:22:00

MySQL數據庫ID字段
點贊
收藏

51CTO技術棧公眾號

九九综合在线| 麻豆网站视频在线观看| 一区二区三区国产盗摄 | 国产精品福利片| 超碰人人人人人人人| 午夜不卡一区| 五月天中文字幕一区二区| 欧美第一黄网| 国产视频在线观看视频| 国产日韩欧美一区| xxxxx成人.com| 亚洲欧美日韩色| 992tv国产精品成人影院| 一区二区三区av电影| 蜜桃视频在线观看成人| 99久久精品无免国产免费| 亚洲一区视频| 欧美成人高清视频| 国产肥白大熟妇bbbb视频| 久久gogo国模啪啪裸体| 91黄色免费看| 18禁网站免费无遮挡无码中文| av电影在线网| 2024国产精品视频| 91老司机精品视频| 日本中文字幕久久| 在线日韩视频| 久久夜色精品国产亚洲aⅴ| 中文精品在线观看| 66精品视频在线观看| 欧美日韩一卡二卡三卡| aa免费在线观看| 97人人爽人人澡人人精品| 国产精品国产三级国产普通话99| 九九九九九精品| 亚洲福利在线观看视频| 久色婷婷小香蕉久久| 日韩免费观看高清| 日韩人妻无码一区二区三区99 | 久久这里只有精品18| 在线观看免费黄色| 国产人伦精品一区二区| 久久精品午夜一区二区福利| 亚洲国产999| 国产精品一区二区在线观看网站 | 中文字字幕在线观看| 久久一区欧美| 欧亚精品中文字幕| 久久久久久少妇| 日韩午夜高潮| 97久久久久久| 日本五十路女优| 亚洲激情午夜| 国内成人精品一区| 国产在线视频二区| 在线高清一区| 91精品国产777在线观看| 日韩女优在线观看| 一本综合久久| 欧美一区二区三区……| 久久中文字幕免费| 久久国产88| 国产精品日韩欧美大师| 中文字幕一区二区人妻痴汉电车| 免费成人在线观看视频| 国产精品视频久久久| 91福利在线观看视频| 国产酒店精品激情| 超碰国产精品久久国产精品99| 亚洲精品字幕在线| 99热在这里有精品免费| 噜噜噜噜噜久久久久久91| 深夜福利在线视频| 国产婷婷色一区二区三区四区| 免费在线成人av电影| 岛国大片在线观看| 国产精品国产三级国产普通话蜜臀 | 污污的视频免费| 成人在线视频www| 日韩精品在线网站| 一起草在线视频| 伊人成综合网伊人222| 一区二区三区视频观看| 多男操一女视频| 欧美三级午夜理伦三级中文幕| 国内精品伊人久久| 日批视频免费观看| 国产精品一区在线观看你懂的| 国产伦精品一区二区三区在线| 日夜干在线视频| 国产精品九色蝌蚪自拍| 国产成人一区二区三区别| 亚洲人成在线网站| 欧美情侣在线播放| 在线免费观看污视频| 欧美日韩国产传媒| 久久久久www| 国产情侣自拍av| 激情都市一区二区| 精品国产乱码久久久久软件| yw视频在线观看| 一区二区国产视频| 国产精品入口免费软件| 99香蕉久久| 色悠悠国产精品| 天天操天天干视频| 国产在线一区二区| 欧美日韩一区二区三| 五月婷婷视频在线观看| 色网站国产精品| 国产人妖在线观看| 第四色成人网| 欧美一区二区三区免费观看| 不卡的日韩av| 国产精品美女一区二区在线观看| 国产v片免费观看| 国产电影一区| 一区二区三区日韩在线| 亚洲久久在线观看| 国产精品77777| 亚洲午夜在线观看| 超碰aⅴ人人做人人爽欧美| 欧美一二三四在线| 综合 欧美 亚洲日本| 亚洲在线免费| 国产一区二区免费电影| 黄视频网站在线| 欧美无砖砖区免费| 熟女俱乐部一区二区| 黄色av成人| 亚洲va欧美va在线观看| 91精品国产综合久久久久久豆腐| 色婷婷精品久久二区二区蜜臂av| 精品1卡二卡三卡四卡老狼| 亚洲女同另类| 成人黄色在线播放| 在线视频自拍| 欧美视频一区在线观看| 强伦人妻一区二区三区| 国产日韩高清一区二区三区在线| 国产精品久久久久久久天堂第1集 国产精品久久久久久久免费大片 国产精品久久久久久久久婷婷 | 日韩一区二区三区视频在线观看| 国产三级aaa| 蜜桃视频在线观看一区二区| 神马影院午夜我不卡影院| 精品国产免费人成网站| 亚洲精品视频中文字幕| 久久久国产精品成人免费| yourporn久久国产精品| 蜜桃传媒一区二区三区| 国产香蕉精品| 久久久噜噜噜久噜久久| 狠狠综合久久av一区二区| 一个色综合网站| 少妇极品熟妇人妻无码| 精品91视频| 好吊妞www.84com只有这里才有精品| 国产丝袜视频在线播放| 亚洲成人动漫在线播放| 日韩av在线播| 久久亚洲捆绑美女| 狠狠操精品视频| 久久国产亚洲| 91亚洲精品在线| 爱福利在线视频| 亚洲精品视频在线观看视频| av黄色在线播放| 国产欧美一区二区三区网站| 最新天堂中文在线| 天天av综合| 国产不卡一区二区三区在线观看| gogo久久| 国产午夜精品视频| 91高潮大合集爽到抽搐| 一区二区三区四区激情| 中文字幕在线永久| 久久激情综合| 大桥未久一区二区三区| 久久99国产精品久久99大师| 国产成人鲁鲁免费视频a| 日本三级视频在线播放| 日韩精品中午字幕| 久久久精品视频网站| 国产精品电影院| 日本一区二区在线观看视频| 久久午夜精品| 黑人巨茎大战欧美白妇| 欧美电影在线观看完整版| 国产精品免费小视频| 色呦呦在线看| 亚洲天堂av在线免费观看| 国产三级小视频| 午夜激情综合网| 999久久久国产| av中文字幕在线不卡| 波多结衣在线观看| 国产精品激情电影| 日韩av免费电影| www.国产精品一区| 国产精品专区第二| 理论不卡电影大全神| 日韩亚洲国产中文字幕| 无码精品在线观看| 欧美一区二区在线视频| 欧美 日韩 精品| 一区二区三区日韩欧美精品| 欧美偷拍一区二区三区| 成人一级黄色片| 毛片毛片毛片毛| 久久久综合网| 国产精品久久久久9999爆乳| 97精品一区| 久久伊人一区| 91成人精品在线| 91精品久久久久久久久久久 | 国产深夜精品福利| 中国色在线日|韩| 欧美丰满少妇xxxxx| 1024国产在线| 亚洲视频在线观看视频| 欧美视频在线观看一区二区三区| 欧美夫妻性生活| 国产精品午夜一区二区| 精品欧美国产一区二区三区| 久久久久国产精品夜夜夜夜夜| 国产精品美女久久久久av爽李琼 | 精品精品久久| 九九九九精品九九九九| 超碰成人免费| www.久久草| 欧美日韩黄网站| 91九色视频在线| 四虎国产精品成人免费影视| 国产精品久久不能| 精品欧美一区二区三区在线观看| 2019av中文字幕| 538视频在线| 性日韩欧美在线视频| 色a资源在线| 色综合久久悠悠| 日韩三级免费| 欧美国产第二页| 美足av综合网| 久久久免费在线观看| 色av手机在线| 欧美国产乱视频| 91高清视频在线观看| 国内伊人久久久久久网站视频| 国产www视频在线观看| 欧美精品videos另类日本| 肉肉视频在线观看| 久久久人成影片一区二区三区观看| 四季久久免费一区二区三区四区| 色综合色综合网色综合| av第一福利在线导航| 国内精品久久久久久久久| 超碰激情在线| 欧美在线视频观看免费网站| 日本综合字幕| 国产精品欧美激情| www一区二区三区| 91久久久在线| 国产精品巨作av| 九色91国产| 色综合久久一区二区三区| 特级黄色录像片| 在线观看视频日韩| 久久久999免费视频| 石原莉奈在线亚洲二区| 日本中文字幕二区| 国产伦理精品不卡| 精品视频站长推荐| 国产视频一区在线观看| www中文在线| 亚洲五码中文字幕| 91玉足脚交嫩脚丫在线播放| 欧美另类z0zxhd电影| 亚洲精品成人区在线观看| 亚洲欧美国产日韩中文字幕| 91吃瓜网在线观看| 欧美第一黄色网| 国产不卡网站| 国产精品成人一区二区网站软件| 亚洲色图五月天| 国产男女无遮挡| 欧美裸体视频| 国产v综合v亚洲欧美久久 | 国产成人精品午夜| 性欧美video另类hd尤物| 成人h视频在线观看| 亚洲精品无吗| 国产日韩欧美大片| 亚洲欧美日本视频在线观看| 欧美在线aaa| 99麻豆久久久国产精品免费| 国产又粗又长又黄的视频| 亚洲国产日韩一级| 最近中文字幕免费观看| 精品久久人人做人人爽| 成人一区二区不卡免费| 色综合老司机第九色激情| av一区在线| 国产精品久久波多野结衣| 色88久久久久高潮综合影院| 麻豆tv在线播放| 精品写真视频在线观看| 亚洲狠狠婷婷综合久久久久图片| 自拍偷拍亚洲综合| 中文字幕一区在线播放| 日韩精品一区二区在线| 色影视在线观看| 欧美做受高潮1| 国产美女撒尿一区二区| 一区二区三区一级片| 美女尤物久久精品| www.四虎在线| 亚洲日本电影在线| 精品无码一区二区三区的天堂| 欧美tickling挠脚心丨vk| 日本美女高清在线观看免费| 热草久综合在线| 精品网站aaa| 奇米777四色影视在线看| 蜜臀va亚洲va欧美va天堂| 国产福利短视频| 亚洲成人精品一区二区| 99精品在线视频观看| 色老头一区二区三区在线观看| 老司机深夜福利在线观看| 粉嫩av免费一区二区三区| 亚洲一区在线| 亚洲欧美视频二区| 国产日产精品1区| 亚州国产精品视频| 亚洲第一视频在线观看| 羞羞的视频在线观看| 91沈先生作品| 久久精品影视| 亚洲天堂伊人网| 亚洲视频一区二区免费在线观看| 在线观看亚洲一区二区| 亚洲亚裔videos黑人hd| 欧美性片在线观看| 日韩在线国产| 青草国产精品久久久久久| 性猛交娇小69hd| 欧美色综合网站| 三区四区电影在线观看| 国产日韩精品一区二区| 99成人在线视频| 在线观看日本www| 亚洲精品欧美专区| 亚洲国产欧美另类| 国模视频一区二区| 亚洲欧美tv| 免费看黄色一级大片| 日本一区二区三区免费乱视频| 久久久久亚洲视频| 色综合伊人色综合网站| 99综合久久| 人妻互换免费中文字幕| 成人国产视频在线观看| 国产微拍精品一区| 亚洲人成网站777色婷婷| 深夜视频一区二区| 熟女熟妇伦久久影院毛片一区二区| 国产一区欧美二区| 久久久久久久伊人| 亚洲片在线资源| 欧美一级免费| 久久av高潮av| 久久网站最新地址| 一卡二卡三卡在线| 欧美激情网友自拍| 综合亚洲自拍| 天天影视色综合| 亚洲国产精品久久不卡毛片| 青青草在线视频免费观看| 国产精品视频内| 欧美三级特黄| 永久免费av无码网站性色av| 91精品视频网| 美女高潮视频在线看| 亚洲精品美女久久7777777| 国产在线播放一区| 久草视频在线观| 日韩视频免费在线观看| 九色丨蝌蚪丨成人| 欧美一级xxxx| 欧美性色视频在线| 毛片在线播放a| 欧美日韩精品免费观看| 国产一区二区精品在线观看| 久久久久亚洲av成人毛片韩| 日韩一区二区av| 美女久久久久| 超碰人人cao| 欧美视频一区二区在线观看| 爱啪啪综合导航| 成人在线观看www|