Skip to content

Commit

Permalink
Added uniqueQualifiers field to ving schema props to implement: allow…
Browse files Browse the repository at this point in the history
… unique indexes within set #114
  • Loading branch information
rizen committed Apr 25, 2024
1 parent fc95d5c commit a3c0f80
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 2 deletions.
1 change: 1 addition & 0 deletions docs/change-log.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ outline: deep
* Added a job handler generator to the CLI.
* Added CLI functions to obliterate, pause, and unpause queues.
* Added CLI functions to list jobs in a queue and kill them.
* Added uniqueQualifiers field to ving schema props to implement: allow unique indexes within set #114

## 2024-04-23
* Created SelectInput component to replace FormSelect. However, you should use FormInput with type select instead of using this directly in most cases.
Expand Down
21 changes: 21 additions & 0 deletions docs/subsystems/ving-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,27 @@ The `length` field is required when the prop is of type `string`, `enum`, and `i

The `unique` field is an optional boolean. When set to `true` a unique index will be created on this prop in the database, and the record will test that the data being set to the prop is unqiue.

##### uniqueQualifiers

The `uniqueQualifiers` field is an optional array of other prop names. It can be used with the `unique` field is set to `true`. Then instead of this prop being unique across the entire table, must be unique amongst the qualifiers. For example, if you had a schema with props that looked like:

```js
{
type: 'string',
name: 'name',
unique: true,
uniqueQualifiers: ['category'],
},
{
type: 'enum',
name: 'category',
default: 'Food',
enums: ['Food','Weapons','Armor'],
},
```

Then each `name` would have to be unique within the specified `category`.

##### filterQuery

An optional boolean that if true will allow searching via the [rest api](rest) for keyword matches against this field. This is an alternative to overriding the `describeListFilter()` method in [VingRecord](ving-record).
Expand Down
10 changes: 9 additions & 1 deletion ving/generator/drizzletable.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@ export const makeBaseTable = (schema) => {
if (prop.type != 'virtual') {
columns.push(`${prop.name}: ${prop.db(prop)}`)
if (prop.unique) {
specialConstraints.push(`${prop.name}Index: uniqueIndex('${prop.name}Index').on(table.${prop.name})`);
if (prop.uniqueQualifiers && prop.uniqueQualifiers.length) {
const fields = [prop.name, ...prop.uniqueQualifiers];
const composite = fields.join('_');
const key = composite.substring(0, 48) + '_' + miniHash(composite) + '_uq';
specialConstraints.push(`${key}: unique('${key}').on(table.${fields.join(', table.')})`);
}
else {
specialConstraints.push(`${prop.name}Index: uniqueIndex('${prop.name}Index').on(table.${prop.name})`);
}
}
if (prop.relation && ['parent', 'sibling'].includes(prop.relation.type)) {
const composite = [schema.tableName, prop.relation.name].join('_');
Expand Down
6 changes: 5 additions & 1 deletion ving/record/VingRecord.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,11 @@ export class VingRecord {
let where = eq(this.table[field.name], params[field.name]);
if (this.isInserted)
where = and(where, ne(this.table.id, this.get('id')));

if (field.uniqueQualifiiers) {
for (const qualifier of field.uniqueQualifiiers) {
where = and(where, eq(this.table[qualifier], params[qualifier] || this.get(qualifier)));
}
}
let count = (await query.where(where))[0].count
if (count > 0) {
ving.log('VingRecord').warning(`${this.get('id')} unique check failed on ${field.name.toString()}`)
Expand Down

0 comments on commit a3c0f80

Please sign in to comment.