1// Copyright (C) MongoDB, Inc. 2017-present.
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may
4// not use this file except in compliance with the License. You may obtain
5// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
7package driver
8
9import (
10	"context"
11
12	"time"
13
14	"go.mongodb.org/mongo-driver/mongo/options"
15	"go.mongodb.org/mongo-driver/x/bsonx"
16	"go.mongodb.org/mongo-driver/x/mongo/driver/session"
17	"go.mongodb.org/mongo-driver/x/mongo/driver/topology"
18	"go.mongodb.org/mongo-driver/x/mongo/driver/uuid"
19	"go.mongodb.org/mongo-driver/x/network/command"
20	"go.mongodb.org/mongo-driver/x/network/description"
21	"go.mongodb.org/mongo-driver/x/network/result"
22)
23
24// CreateIndexes handles the full cycle dispatch and execution of a createIndexes
25// command against the provided topology.
26func CreateIndexes(
27	ctx context.Context,
28	cmd command.CreateIndexes,
29	topo *topology.Topology,
30	selector description.ServerSelector,
31	clientID uuid.UUID,
32	pool *session.Pool,
33	opts ...*options.CreateIndexesOptions,
34) (result.CreateIndexes, error) {
35
36	ss, err := topo.SelectServer(ctx, selector)
37	if err != nil {
38		return result.CreateIndexes{}, err
39	}
40
41	desc := ss.Description()
42	if desc.WireVersion.Max < 5 && hasCollation(cmd) {
43		return result.CreateIndexes{}, ErrCollation
44	}
45
46	conn, err := ss.Connection(ctx)
47	if err != nil {
48		return result.CreateIndexes{}, err
49	}
50	defer conn.Close()
51
52	cio := options.MergeCreateIndexesOptions(opts...)
53	if cio.MaxTime != nil {
54		cmd.Opts = append(cmd.Opts, bsonx.Elem{"maxTimeMS", bsonx.Int64(int64(*cio.MaxTime / time.Millisecond))})
55	}
56
57	// If no explicit session and deployment supports sessions, start implicit session.
58	if cmd.Session == nil && topo.SupportsSessions() {
59		cmd.Session, err = session.NewClientSession(pool, clientID, session.Implicit)
60		if err != nil {
61			return result.CreateIndexes{}, err
62		}
63		defer cmd.Session.EndSession()
64	}
65
66	return cmd.RoundTrip(ctx, ss.Description(), conn)
67}
68
69func hasCollation(cmd command.CreateIndexes) bool {
70	for _, ind := range cmd.Indexes {
71		if _, err := ind.Document().LookupErr("collation"); err == nil {
72			return true
73		}
74	}
75
76	return false
77}
78