Copyright 2021 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package postgres

import (
	
	
	
	
	
	

	
	
	
	
)
GetLatestMajorPathForV1Path reports the latest unit path in the series for the given v1path. It also returns the major version for that path.
func ( *DB) ( context.Context,  string) ( string,  int,  error) {
	defer derrors.WrapStack(&, "DB.GetLatestPathForV1Path(ctx, %q)", )
	 := `
		SELECT p.path, m.series_path
		FROM paths p
		INNER JOIN units u ON u.path_id = p.id
		INNER JOIN modules m ON u.module_id = m.id
		WHERE u.v1path_id = (
			SELECT p.id
			FROM paths p
			INNER JOIN units u ON u.v1path_id = p.id
			WHERE p.path = $1
			ORDER BY p.path DESC
			LIMIT 1
		);`
	 := map[string]string{} // from unit path to series path
	 = .db.RunQuery(, , func( *sql.Rows) error {
		var ,  string
		if  := .Scan(&, &);  != nil {
			return 
		}
		[] = 
		return nil
	}, )
	if  != nil {
		return "", 0, 
	}

	var (
		     int
		 string
	)
Trim the series path and suffix from the unit path. Keep only the N following vN.
		 := internal.Suffix(, )
		 := strings.TrimSuffix(, "/"+)
		,  := internal.SeriesPathAndMajorVersion()
		if  == 0 {
			return "", 0, fmt.Errorf("bad module path %q", )
		}
		if  <=  {
			 = 
			 = 
		}
	}
Return 1 as the major version for all v0 or v1 majPaths.
		 = 1
	}
	return , , nil
}
upsertPath adds path into the paths table if it does not exist, and returns its ID either way. It assumes it is running inside a transaction.
Doing the select first and then the insert led to uniqueness constraint violations even with fully serializable transactions; see https://www.postgresql.org/message-id/CAOqyxwL4E_JmUScYrnwd0_sOtm3bt4c7G%2B%2BUiD2PnmdGJFiqyQ%40mail.gmail.com. If the upsert is done first and then the select, then everything works fine.
	defer derrors.WrapStack(&, "upsertPath(%q)", )

	if ,  := .Exec(, `LOCK TABLE paths IN EXCLUSIVE MODE`);  != nil {
		return 0, 
	}
	 = .QueryRow(,
		`INSERT INTO paths (path) VALUES ($1) ON CONFLICT DO NOTHING RETURNING id`,
		).Scan(&)
	if  == sql.ErrNoRows {
		 = .QueryRow(,
			`SELECT id FROM paths WHERE path = $1`,
			).Scan(&)
		if  == sql.ErrNoRows {
			return 0, errors.New("got no rows; shouldn't happen")
		}
	}
	if  != nil {
		return 0, 
	}
	if  == 0 {
		return 0, errors.New("zero ID")
	}
	return , nil
}
upsertPaths adds all the paths to the paths table if they aren't already there, and returns their ID either way. It assumes it is running inside a transaction.
func ( context.Context,  *database.DB,  []string) ( map[string]int,  error) {
	defer derrors.WrapStack(&, "upsertPaths(%d paths)", len())

	 = map[string]int{}
	 := func( *sql.Rows) error {
		var (
			 int
			   string
		)
		if  := .Scan(&, &);  != nil {
			return 
		}
		[] = 
		return nil
	}

	if  := .RunQuery(, `SELECT id, path FROM paths WHERE path = ANY($1)`,
		, pq.Array());  != nil {
		return nil, 
	}
Insert any unit paths that we don't already have.
	var  []interface{}
	for ,  := range  {
		if ,  := []; ! {
			 = append(, )
		}
	}
Sort to avoid deadlock.
Insert data into the paths table.
		 := []string{"path"}
		 := []string{"id", "path"}
		if  := .BulkInsertReturning(, "paths", , ,
			database.OnConflictDoNothing, , );  != nil {
			return nil, 
		}
	}
	return , nil
}

func ( context.Context,  *database.DB,  string) ( int,  error) {
	 = .QueryRow(,
		`SELECT id FROM paths WHERE path = $1`,
		).Scan(&)
	return ,