<commit_before>package storage

import (
	"database/sql"

	"github.com/golang/glog"
	"github.com/juju/errors"
	_ "github.com/lib/pq"
)

func CreateTag(
	tx *sql.Tx, ownerID, parentTagID int, names []string,
) (tagID int, err error) {
	glog.Infof("len names=%d", len(names))
	if len(names) == 0 {
		glog.Infof("returning error!")
		return 0, errors.Errorf("tag should have at least one name")
	}

	var pParent interface{}

	if parentTagID > 0 {
		pParent = parentTagID
	}

	err = tx.QueryRow(
		"INSERT INTO tags (parent_id, owner_id) VALUES ($1, $2) RETURNING id",
		pParent, ownerID,
	).Scan(&tagID)
	if err != nil {
		return 0, errors.Trace(err)
	}

	for _, name := range names {
		// TODO: ensure that the tag with this name does not already exists
		// (in the given parent tag and owned by the same user, of course).
		// Either do that in Go or, if possible, in SQL

		// Only root tag is allowed to have an empty name
		if name == "" && pParent != nil {
			return 0, errors.Errorf("Tag name can't be empty")
		}

		_, err := tx.Exec(
			"INSERT INTO tag_names (tag_id, name) VALUES ($1, $2)",
			tagID, name,
		)
		if err != nil {
			return 0, errors.Trace(err)
		}
	}

	return tagID, nil
}

func GetRootTagID(tx *sql.Tx, ownerID int) (int, error) {
	var rootTagID int
	err := tx.QueryRow(
		"SELECT id FROM tags WHERE owner_id = $1 AND parent_id IS NULL",
		ownerID,
	).Scan(&rootTagID)
	if err != nil {
		return 0, errors.Trace(err)
	}

	return rootTagID, nil
}
<commit_msg>Check if tag with the given name already exists<commit_after>package storage

import (
	"database/sql"

	hh "dmitryfrank.com/geekmarks/server/httphelper"
	"github.com/golang/glog"
	"github.com/juju/errors"
	_ "github.com/lib/pq"
)

func CreateTag(
	tx *sql.Tx, ownerID, parentTagID int, names []string,
) (tagID int, err error) {
	glog.Infof("len names=%d", len(names))
	if len(names) == 0 {
		glog.Infof("returning error!")
		return 0, errors.Errorf("tag should have at least one name")
	}

	var pParent interface{}

	if parentTagID > 0 {
		pParent = parentTagID
	}

	err = tx.QueryRow(
		"INSERT INTO tags (parent_id, owner_id) VALUES ($1, $2) RETURNING id",
		pParent, ownerID,
	).Scan(&tagID)
	if err != nil {
		return 0, errors.Trace(err)
	}

	for _, name := range names {
		// Check if tag with the given name already exists under the parent tag
		// TODO: instead of calling it here manually, maybe add a SQL trigger?
		exists, err := tagExists(tx, parentTagID, name)
		if err != nil {
			return 0, errors.Trace(err)
		}
		if exists {
			return 0, errors.Errorf("Tag with the name %q already exists", name)
		}

		// Only root tag is allowed to have an empty name
		if name == "" && pParent != nil {
			return 0, errors.Errorf("Tag name can't be empty")
		}

		_, err = tx.Exec(
			"INSERT INTO tag_names (tag_id, name) VALUES ($1, $2)",
			tagID, name,
		)
		if err != nil {
			return 0, errors.Trace(err)
		}
	}

	return tagID, nil
}

func GetRootTagID(tx *sql.Tx, ownerID int) (int, error) {
	var rootTagID int
	err := tx.QueryRow(
		"SELECT id FROM tags WHERE owner_id = $1 AND parent_id IS NULL",
		ownerID,
	).Scan(&rootTagID)
	if err != nil {
		return 0, errors.Trace(err)
	}

	return rootTagID, nil
}

// tagExists returns whether the tag with the given name already exists under
// the given parent tag.
func tagExists(tx *sql.Tx, parentTagID int, name string) (ok bool, err error) {
	var cnt int
	err = tx.QueryRow(`
		SELECT COUNT(t.id)
			FROM tag_names n
			JOIN tags t ON n.tag_id = t.id
			WHERE t.parent_id = $1 and n.name = $2
	`, parentTagID, name,
	).Scan(&cnt)
	if err != nil {
		return false, hh.MakeInternalServerError(
			err, "checking whether tag already exists",
		)
	}

	return cnt > 0, nil
}

{'fraction_non_alphanumeric': 0.12911051212938005, 'fraction_numerical': 0.007816711590296496, 'mean_word_length': 3.325174825174825, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 6, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2812686', 'n_tokens_mistral': 1467, 'n_tokens_neox': 1338, 'n_words': 453}