arkormx 0.1.10 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +195 -0
- package/dist/index.d.cts +73 -0
- package/dist/index.d.mts +73 -0
- package/dist/index.mjs +195 -0
- package/package.json +4 -2
package/dist/index.cjs
CHANGED
|
@@ -3664,6 +3664,99 @@ var QueryBuilder = class QueryBuilder {
|
|
|
3664
3664
|
return this.model.hydrate(created);
|
|
3665
3665
|
}
|
|
3666
3666
|
/**
|
|
3667
|
+
* Creates multiple records and returns hydrated model instances.
|
|
3668
|
+
*
|
|
3669
|
+
* @param values
|
|
3670
|
+
* @returns
|
|
3671
|
+
*/
|
|
3672
|
+
async createMany(values) {
|
|
3673
|
+
if (values.length === 0) return [];
|
|
3674
|
+
return await Promise.all(values.map(async (value) => await this.create(value)));
|
|
3675
|
+
}
|
|
3676
|
+
/**
|
|
3677
|
+
* Insert one or more records.
|
|
3678
|
+
*
|
|
3679
|
+
* @param values
|
|
3680
|
+
* @returns
|
|
3681
|
+
*/
|
|
3682
|
+
async insert(values) {
|
|
3683
|
+
const payloads = this.normalizeInsertPayloads(values);
|
|
3684
|
+
if (payloads.length === 0) return true;
|
|
3685
|
+
const delegate = this.delegate;
|
|
3686
|
+
if (typeof delegate.createMany === "function") {
|
|
3687
|
+
await delegate.createMany({ data: payloads });
|
|
3688
|
+
return true;
|
|
3689
|
+
}
|
|
3690
|
+
await Promise.all(payloads.map(async (payload) => {
|
|
3691
|
+
await this.delegate.create({ data: payload });
|
|
3692
|
+
}));
|
|
3693
|
+
return true;
|
|
3694
|
+
}
|
|
3695
|
+
/**
|
|
3696
|
+
* Insert one or more records while ignoring insertion errors.
|
|
3697
|
+
*
|
|
3698
|
+
* @param values
|
|
3699
|
+
* @returns
|
|
3700
|
+
*/
|
|
3701
|
+
async insertOrIgnore(values) {
|
|
3702
|
+
const payloads = this.normalizeInsertPayloads(values);
|
|
3703
|
+
if (payloads.length === 0) return 0;
|
|
3704
|
+
const delegate = this.delegate;
|
|
3705
|
+
if (typeof delegate.createMany === "function") {
|
|
3706
|
+
const result = await delegate.createMany({
|
|
3707
|
+
data: payloads,
|
|
3708
|
+
skipDuplicates: true
|
|
3709
|
+
});
|
|
3710
|
+
return this.resolveAffectedCount(result, payloads.length);
|
|
3711
|
+
}
|
|
3712
|
+
let inserted = 0;
|
|
3713
|
+
for (const payload of payloads) try {
|
|
3714
|
+
await this.delegate.create({ data: payload });
|
|
3715
|
+
inserted += 1;
|
|
3716
|
+
} catch {
|
|
3717
|
+
continue;
|
|
3718
|
+
}
|
|
3719
|
+
return inserted;
|
|
3720
|
+
}
|
|
3721
|
+
/**
|
|
3722
|
+
* Insert a record and return its primary key value.
|
|
3723
|
+
*
|
|
3724
|
+
* @param values
|
|
3725
|
+
* @param sequence
|
|
3726
|
+
* @returns
|
|
3727
|
+
*/
|
|
3728
|
+
async insertGetId(values, sequence) {
|
|
3729
|
+
const created = await this.delegate.create({ data: values });
|
|
3730
|
+
const key = sequence ?? "id";
|
|
3731
|
+
if (!(key in created)) throw new ArkormException(`Inserted record does not contain key [${key}].`);
|
|
3732
|
+
return created[key];
|
|
3733
|
+
}
|
|
3734
|
+
/**
|
|
3735
|
+
* Insert records using values produced by another query/source.
|
|
3736
|
+
*
|
|
3737
|
+
* @param columns
|
|
3738
|
+
* @param query
|
|
3739
|
+
* @returns
|
|
3740
|
+
*/
|
|
3741
|
+
async insertUsing(columns, query) {
|
|
3742
|
+
const rows = await this.resolveInsertUsingRows(columns, query);
|
|
3743
|
+
if (rows.length === 0) return 0;
|
|
3744
|
+
await this.insert(rows);
|
|
3745
|
+
return rows.length;
|
|
3746
|
+
}
|
|
3747
|
+
/**
|
|
3748
|
+
* Insert records using values produced by another query/source while ignoring insertion errors.
|
|
3749
|
+
*
|
|
3750
|
+
* @param columns
|
|
3751
|
+
* @param query
|
|
3752
|
+
* @returns
|
|
3753
|
+
*/
|
|
3754
|
+
async insertOrIgnoreUsing(columns, query) {
|
|
3755
|
+
const rows = await this.resolveInsertUsingRows(columns, query);
|
|
3756
|
+
if (rows.length === 0) return 0;
|
|
3757
|
+
return this.insertOrIgnore(rows);
|
|
3758
|
+
}
|
|
3759
|
+
/**
|
|
3667
3760
|
* Updates records matching the current query constraints with the
|
|
3668
3761
|
* specified data and returns the updated record(s) as model instance(s).
|
|
3669
3762
|
*
|
|
@@ -3681,6 +3774,71 @@ var QueryBuilder = class QueryBuilder {
|
|
|
3681
3774
|
return this.model.hydrate(updated);
|
|
3682
3775
|
}
|
|
3683
3776
|
/**
|
|
3777
|
+
* Update records using update-many semantics when available.
|
|
3778
|
+
*
|
|
3779
|
+
* @param data
|
|
3780
|
+
* @returns
|
|
3781
|
+
*/
|
|
3782
|
+
async updateFrom(data) {
|
|
3783
|
+
const where = this.buildWhere();
|
|
3784
|
+
if (!where) throw new ArkormException("Update requires a where clause.");
|
|
3785
|
+
const delegate = this.delegate;
|
|
3786
|
+
if (typeof delegate.updateMany === "function") {
|
|
3787
|
+
const result = await delegate.updateMany({
|
|
3788
|
+
where,
|
|
3789
|
+
data
|
|
3790
|
+
});
|
|
3791
|
+
return this.resolveAffectedCount(result, 0);
|
|
3792
|
+
}
|
|
3793
|
+
await this.update(data);
|
|
3794
|
+
return 1;
|
|
3795
|
+
}
|
|
3796
|
+
/**
|
|
3797
|
+
* Insert a record when no match exists, otherwise update the matching record.
|
|
3798
|
+
*
|
|
3799
|
+
* @param attributes
|
|
3800
|
+
* @param values
|
|
3801
|
+
* @returns
|
|
3802
|
+
*/
|
|
3803
|
+
async updateOrInsert(attributes, values = {}) {
|
|
3804
|
+
const exists = await this.delegate.findFirst({ where: attributes }) != null;
|
|
3805
|
+
const resolvedValues = typeof values === "function" ? await values(exists) : values;
|
|
3806
|
+
if (!exists) {
|
|
3807
|
+
await this.delegate.create({ data: {
|
|
3808
|
+
...attributes,
|
|
3809
|
+
...resolvedValues
|
|
3810
|
+
} });
|
|
3811
|
+
return true;
|
|
3812
|
+
}
|
|
3813
|
+
return await this.clone().where(attributes).update(resolvedValues) != null;
|
|
3814
|
+
}
|
|
3815
|
+
/**
|
|
3816
|
+
* Insert new records or update existing records by one or more unique keys.
|
|
3817
|
+
*
|
|
3818
|
+
* @param values
|
|
3819
|
+
* @param uniqueBy
|
|
3820
|
+
* @param update
|
|
3821
|
+
* @returns
|
|
3822
|
+
*/
|
|
3823
|
+
async upsert(values, uniqueBy, update = null) {
|
|
3824
|
+
if (values.length === 0) return 0;
|
|
3825
|
+
const uniqueKeys = Array.isArray(uniqueBy) ? uniqueBy : [uniqueBy];
|
|
3826
|
+
let affected = 0;
|
|
3827
|
+
for (const row of values) {
|
|
3828
|
+
const attributes = uniqueKeys.reduce((all, key) => {
|
|
3829
|
+
all[key] = row[key];
|
|
3830
|
+
return all;
|
|
3831
|
+
}, {});
|
|
3832
|
+
const updatePayload = (update ?? Object.keys(row).filter((key) => !uniqueKeys.includes(key))).reduce((all, key) => {
|
|
3833
|
+
if (key in row) all[key] = row[key];
|
|
3834
|
+
return all;
|
|
3835
|
+
}, {});
|
|
3836
|
+
await this.updateOrInsert(attributes, updatePayload);
|
|
3837
|
+
affected += 1;
|
|
3838
|
+
}
|
|
3839
|
+
return affected;
|
|
3840
|
+
}
|
|
3841
|
+
/**
|
|
3684
3842
|
* Deletes records matching the current query constraints and returns
|
|
3685
3843
|
* the deleted record(s) as model instance(s).
|
|
3686
3844
|
*
|
|
@@ -3719,6 +3877,43 @@ var QueryBuilder = class QueryBuilder {
|
|
|
3719
3877
|
async doesntExist() {
|
|
3720
3878
|
return !await this.exists();
|
|
3721
3879
|
}
|
|
3880
|
+
normalizeInsertPayloads(values) {
|
|
3881
|
+
if (Array.isArray(values)) return values;
|
|
3882
|
+
return [values];
|
|
3883
|
+
}
|
|
3884
|
+
resolveAffectedCount(result, fallback) {
|
|
3885
|
+
if (typeof result === "number") return result;
|
|
3886
|
+
if (result && typeof result === "object" && "count" in result) {
|
|
3887
|
+
const candidate = result.count;
|
|
3888
|
+
if (typeof candidate === "number") return candidate;
|
|
3889
|
+
}
|
|
3890
|
+
return fallback;
|
|
3891
|
+
}
|
|
3892
|
+
async resolveInsertUsingRows(columns, query) {
|
|
3893
|
+
const resolvedQuery = typeof query === "function" ? await query() : query;
|
|
3894
|
+
return (await this.resolveInsertUsingSource(resolvedQuery)).map((row) => {
|
|
3895
|
+
return columns.reduce((record, column) => {
|
|
3896
|
+
record[column] = row[column];
|
|
3897
|
+
return record;
|
|
3898
|
+
}, {});
|
|
3899
|
+
});
|
|
3900
|
+
}
|
|
3901
|
+
async resolveInsertUsingSource(source) {
|
|
3902
|
+
if (source && typeof source === "object") {
|
|
3903
|
+
const asBuilder = source;
|
|
3904
|
+
if (typeof asBuilder.get === "function") {
|
|
3905
|
+
const collection = await asBuilder.get();
|
|
3906
|
+
if (typeof collection.all === "function") return collection.all().map((item) => {
|
|
3907
|
+
const asModel = item;
|
|
3908
|
+
if (typeof asModel.getRawAttributes === "function") return asModel.getRawAttributes();
|
|
3909
|
+
return item;
|
|
3910
|
+
});
|
|
3911
|
+
}
|
|
3912
|
+
if (Array.isArray(source)) return source;
|
|
3913
|
+
}
|
|
3914
|
+
if (Array.isArray(source)) return source;
|
|
3915
|
+
throw new ArkormException("insertUsing expects a query builder, array of records, or async resolver.");
|
|
3916
|
+
}
|
|
3722
3917
|
/**
|
|
3723
3918
|
* Execute callback when no records exist.
|
|
3724
3919
|
*
|
package/dist/index.d.cts
CHANGED
|
@@ -1477,6 +1477,51 @@ declare class QueryBuilder<TModel, TDelegate extends PrismaDelegateLike = Prisma
|
|
|
1477
1477
|
* @returns
|
|
1478
1478
|
*/
|
|
1479
1479
|
create(data: DelegateCreateData<TDelegate>): Promise<TModel>;
|
|
1480
|
+
/**
|
|
1481
|
+
* Creates multiple records and returns hydrated model instances.
|
|
1482
|
+
*
|
|
1483
|
+
* @param values
|
|
1484
|
+
* @returns
|
|
1485
|
+
*/
|
|
1486
|
+
createMany(values: DelegateCreateData<TDelegate>[]): Promise<TModel[]>;
|
|
1487
|
+
/**
|
|
1488
|
+
* Insert one or more records.
|
|
1489
|
+
*
|
|
1490
|
+
* @param values
|
|
1491
|
+
* @returns
|
|
1492
|
+
*/
|
|
1493
|
+
insert(values: DelegateCreateData<TDelegate> | DelegateCreateData<TDelegate>[]): Promise<boolean>;
|
|
1494
|
+
/**
|
|
1495
|
+
* Insert one or more records while ignoring insertion errors.
|
|
1496
|
+
*
|
|
1497
|
+
* @param values
|
|
1498
|
+
* @returns
|
|
1499
|
+
*/
|
|
1500
|
+
insertOrIgnore(values: DelegateCreateData<TDelegate> | DelegateCreateData<TDelegate>[]): Promise<number>;
|
|
1501
|
+
/**
|
|
1502
|
+
* Insert a record and return its primary key value.
|
|
1503
|
+
*
|
|
1504
|
+
* @param values
|
|
1505
|
+
* @param sequence
|
|
1506
|
+
* @returns
|
|
1507
|
+
*/
|
|
1508
|
+
insertGetId(values: DelegateCreateData<TDelegate>, sequence?: string | null): Promise<unknown>;
|
|
1509
|
+
/**
|
|
1510
|
+
* Insert records using values produced by another query/source.
|
|
1511
|
+
*
|
|
1512
|
+
* @param columns
|
|
1513
|
+
* @param query
|
|
1514
|
+
* @returns
|
|
1515
|
+
*/
|
|
1516
|
+
insertUsing(columns: string[], query: unknown): Promise<number>;
|
|
1517
|
+
/**
|
|
1518
|
+
* Insert records using values produced by another query/source while ignoring insertion errors.
|
|
1519
|
+
*
|
|
1520
|
+
* @param columns
|
|
1521
|
+
* @param query
|
|
1522
|
+
* @returns
|
|
1523
|
+
*/
|
|
1524
|
+
insertOrIgnoreUsing(columns: string[], query: unknown): Promise<number>;
|
|
1480
1525
|
/**
|
|
1481
1526
|
* Updates records matching the current query constraints with the
|
|
1482
1527
|
* specified data and returns the updated record(s) as model instance(s).
|
|
@@ -1485,6 +1530,30 @@ declare class QueryBuilder<TModel, TDelegate extends PrismaDelegateLike = Prisma
|
|
|
1485
1530
|
* @returns
|
|
1486
1531
|
*/
|
|
1487
1532
|
update(data: DelegateUpdateData<TDelegate>): Promise<TModel>;
|
|
1533
|
+
/**
|
|
1534
|
+
* Update records using update-many semantics when available.
|
|
1535
|
+
*
|
|
1536
|
+
* @param data
|
|
1537
|
+
* @returns
|
|
1538
|
+
*/
|
|
1539
|
+
updateFrom(data: DelegateUpdateData<TDelegate>): Promise<number>;
|
|
1540
|
+
/**
|
|
1541
|
+
* Insert a record when no match exists, otherwise update the matching record.
|
|
1542
|
+
*
|
|
1543
|
+
* @param attributes
|
|
1544
|
+
* @param values
|
|
1545
|
+
* @returns
|
|
1546
|
+
*/
|
|
1547
|
+
updateOrInsert(attributes: Record<string, unknown>, values?: Record<string, unknown> | ((exists: boolean) => Record<string, unknown> | Promise<Record<string, unknown>>)): Promise<boolean>;
|
|
1548
|
+
/**
|
|
1549
|
+
* Insert new records or update existing records by one or more unique keys.
|
|
1550
|
+
*
|
|
1551
|
+
* @param values
|
|
1552
|
+
* @param uniqueBy
|
|
1553
|
+
* @param update
|
|
1554
|
+
* @returns
|
|
1555
|
+
*/
|
|
1556
|
+
upsert(values: Array<Record<string, unknown>>, uniqueBy: string | string[], update?: string[] | null): Promise<number>;
|
|
1488
1557
|
/**
|
|
1489
1558
|
* Deletes records matching the current query constraints and returns
|
|
1490
1559
|
* the deleted record(s) as model instance(s).
|
|
@@ -1510,6 +1579,10 @@ declare class QueryBuilder<TModel, TDelegate extends PrismaDelegateLike = Prisma
|
|
|
1510
1579
|
* @returns
|
|
1511
1580
|
*/
|
|
1512
1581
|
doesntExist(): Promise<boolean>;
|
|
1582
|
+
private normalizeInsertPayloads;
|
|
1583
|
+
private resolveAffectedCount;
|
|
1584
|
+
private resolveInsertUsingRows;
|
|
1585
|
+
private resolveInsertUsingSource;
|
|
1513
1586
|
/**
|
|
1514
1587
|
* Execute callback when no records exist.
|
|
1515
1588
|
*
|
package/dist/index.d.mts
CHANGED
|
@@ -1477,6 +1477,51 @@ declare class QueryBuilder<TModel, TDelegate extends PrismaDelegateLike = Prisma
|
|
|
1477
1477
|
* @returns
|
|
1478
1478
|
*/
|
|
1479
1479
|
create(data: DelegateCreateData<TDelegate>): Promise<TModel>;
|
|
1480
|
+
/**
|
|
1481
|
+
* Creates multiple records and returns hydrated model instances.
|
|
1482
|
+
*
|
|
1483
|
+
* @param values
|
|
1484
|
+
* @returns
|
|
1485
|
+
*/
|
|
1486
|
+
createMany(values: DelegateCreateData<TDelegate>[]): Promise<TModel[]>;
|
|
1487
|
+
/**
|
|
1488
|
+
* Insert one or more records.
|
|
1489
|
+
*
|
|
1490
|
+
* @param values
|
|
1491
|
+
* @returns
|
|
1492
|
+
*/
|
|
1493
|
+
insert(values: DelegateCreateData<TDelegate> | DelegateCreateData<TDelegate>[]): Promise<boolean>;
|
|
1494
|
+
/**
|
|
1495
|
+
* Insert one or more records while ignoring insertion errors.
|
|
1496
|
+
*
|
|
1497
|
+
* @param values
|
|
1498
|
+
* @returns
|
|
1499
|
+
*/
|
|
1500
|
+
insertOrIgnore(values: DelegateCreateData<TDelegate> | DelegateCreateData<TDelegate>[]): Promise<number>;
|
|
1501
|
+
/**
|
|
1502
|
+
* Insert a record and return its primary key value.
|
|
1503
|
+
*
|
|
1504
|
+
* @param values
|
|
1505
|
+
* @param sequence
|
|
1506
|
+
* @returns
|
|
1507
|
+
*/
|
|
1508
|
+
insertGetId(values: DelegateCreateData<TDelegate>, sequence?: string | null): Promise<unknown>;
|
|
1509
|
+
/**
|
|
1510
|
+
* Insert records using values produced by another query/source.
|
|
1511
|
+
*
|
|
1512
|
+
* @param columns
|
|
1513
|
+
* @param query
|
|
1514
|
+
* @returns
|
|
1515
|
+
*/
|
|
1516
|
+
insertUsing(columns: string[], query: unknown): Promise<number>;
|
|
1517
|
+
/**
|
|
1518
|
+
* Insert records using values produced by another query/source while ignoring insertion errors.
|
|
1519
|
+
*
|
|
1520
|
+
* @param columns
|
|
1521
|
+
* @param query
|
|
1522
|
+
* @returns
|
|
1523
|
+
*/
|
|
1524
|
+
insertOrIgnoreUsing(columns: string[], query: unknown): Promise<number>;
|
|
1480
1525
|
/**
|
|
1481
1526
|
* Updates records matching the current query constraints with the
|
|
1482
1527
|
* specified data and returns the updated record(s) as model instance(s).
|
|
@@ -1485,6 +1530,30 @@ declare class QueryBuilder<TModel, TDelegate extends PrismaDelegateLike = Prisma
|
|
|
1485
1530
|
* @returns
|
|
1486
1531
|
*/
|
|
1487
1532
|
update(data: DelegateUpdateData<TDelegate>): Promise<TModel>;
|
|
1533
|
+
/**
|
|
1534
|
+
* Update records using update-many semantics when available.
|
|
1535
|
+
*
|
|
1536
|
+
* @param data
|
|
1537
|
+
* @returns
|
|
1538
|
+
*/
|
|
1539
|
+
updateFrom(data: DelegateUpdateData<TDelegate>): Promise<number>;
|
|
1540
|
+
/**
|
|
1541
|
+
* Insert a record when no match exists, otherwise update the matching record.
|
|
1542
|
+
*
|
|
1543
|
+
* @param attributes
|
|
1544
|
+
* @param values
|
|
1545
|
+
* @returns
|
|
1546
|
+
*/
|
|
1547
|
+
updateOrInsert(attributes: Record<string, unknown>, values?: Record<string, unknown> | ((exists: boolean) => Record<string, unknown> | Promise<Record<string, unknown>>)): Promise<boolean>;
|
|
1548
|
+
/**
|
|
1549
|
+
* Insert new records or update existing records by one or more unique keys.
|
|
1550
|
+
*
|
|
1551
|
+
* @param values
|
|
1552
|
+
* @param uniqueBy
|
|
1553
|
+
* @param update
|
|
1554
|
+
* @returns
|
|
1555
|
+
*/
|
|
1556
|
+
upsert(values: Array<Record<string, unknown>>, uniqueBy: string | string[], update?: string[] | null): Promise<number>;
|
|
1488
1557
|
/**
|
|
1489
1558
|
* Deletes records matching the current query constraints and returns
|
|
1490
1559
|
* the deleted record(s) as model instance(s).
|
|
@@ -1510,6 +1579,10 @@ declare class QueryBuilder<TModel, TDelegate extends PrismaDelegateLike = Prisma
|
|
|
1510
1579
|
* @returns
|
|
1511
1580
|
*/
|
|
1512
1581
|
doesntExist(): Promise<boolean>;
|
|
1582
|
+
private normalizeInsertPayloads;
|
|
1583
|
+
private resolveAffectedCount;
|
|
1584
|
+
private resolveInsertUsingRows;
|
|
1585
|
+
private resolveInsertUsingSource;
|
|
1513
1586
|
/**
|
|
1514
1587
|
* Execute callback when no records exist.
|
|
1515
1588
|
*
|
package/dist/index.mjs
CHANGED
|
@@ -3635,6 +3635,99 @@ var QueryBuilder = class QueryBuilder {
|
|
|
3635
3635
|
return this.model.hydrate(created);
|
|
3636
3636
|
}
|
|
3637
3637
|
/**
|
|
3638
|
+
* Creates multiple records and returns hydrated model instances.
|
|
3639
|
+
*
|
|
3640
|
+
* @param values
|
|
3641
|
+
* @returns
|
|
3642
|
+
*/
|
|
3643
|
+
async createMany(values) {
|
|
3644
|
+
if (values.length === 0) return [];
|
|
3645
|
+
return await Promise.all(values.map(async (value) => await this.create(value)));
|
|
3646
|
+
}
|
|
3647
|
+
/**
|
|
3648
|
+
* Insert one or more records.
|
|
3649
|
+
*
|
|
3650
|
+
* @param values
|
|
3651
|
+
* @returns
|
|
3652
|
+
*/
|
|
3653
|
+
async insert(values) {
|
|
3654
|
+
const payloads = this.normalizeInsertPayloads(values);
|
|
3655
|
+
if (payloads.length === 0) return true;
|
|
3656
|
+
const delegate = this.delegate;
|
|
3657
|
+
if (typeof delegate.createMany === "function") {
|
|
3658
|
+
await delegate.createMany({ data: payloads });
|
|
3659
|
+
return true;
|
|
3660
|
+
}
|
|
3661
|
+
await Promise.all(payloads.map(async (payload) => {
|
|
3662
|
+
await this.delegate.create({ data: payload });
|
|
3663
|
+
}));
|
|
3664
|
+
return true;
|
|
3665
|
+
}
|
|
3666
|
+
/**
|
|
3667
|
+
* Insert one or more records while ignoring insertion errors.
|
|
3668
|
+
*
|
|
3669
|
+
* @param values
|
|
3670
|
+
* @returns
|
|
3671
|
+
*/
|
|
3672
|
+
async insertOrIgnore(values) {
|
|
3673
|
+
const payloads = this.normalizeInsertPayloads(values);
|
|
3674
|
+
if (payloads.length === 0) return 0;
|
|
3675
|
+
const delegate = this.delegate;
|
|
3676
|
+
if (typeof delegate.createMany === "function") {
|
|
3677
|
+
const result = await delegate.createMany({
|
|
3678
|
+
data: payloads,
|
|
3679
|
+
skipDuplicates: true
|
|
3680
|
+
});
|
|
3681
|
+
return this.resolveAffectedCount(result, payloads.length);
|
|
3682
|
+
}
|
|
3683
|
+
let inserted = 0;
|
|
3684
|
+
for (const payload of payloads) try {
|
|
3685
|
+
await this.delegate.create({ data: payload });
|
|
3686
|
+
inserted += 1;
|
|
3687
|
+
} catch {
|
|
3688
|
+
continue;
|
|
3689
|
+
}
|
|
3690
|
+
return inserted;
|
|
3691
|
+
}
|
|
3692
|
+
/**
|
|
3693
|
+
* Insert a record and return its primary key value.
|
|
3694
|
+
*
|
|
3695
|
+
* @param values
|
|
3696
|
+
* @param sequence
|
|
3697
|
+
* @returns
|
|
3698
|
+
*/
|
|
3699
|
+
async insertGetId(values, sequence) {
|
|
3700
|
+
const created = await this.delegate.create({ data: values });
|
|
3701
|
+
const key = sequence ?? "id";
|
|
3702
|
+
if (!(key in created)) throw new ArkormException(`Inserted record does not contain key [${key}].`);
|
|
3703
|
+
return created[key];
|
|
3704
|
+
}
|
|
3705
|
+
/**
|
|
3706
|
+
* Insert records using values produced by another query/source.
|
|
3707
|
+
*
|
|
3708
|
+
* @param columns
|
|
3709
|
+
* @param query
|
|
3710
|
+
* @returns
|
|
3711
|
+
*/
|
|
3712
|
+
async insertUsing(columns, query) {
|
|
3713
|
+
const rows = await this.resolveInsertUsingRows(columns, query);
|
|
3714
|
+
if (rows.length === 0) return 0;
|
|
3715
|
+
await this.insert(rows);
|
|
3716
|
+
return rows.length;
|
|
3717
|
+
}
|
|
3718
|
+
/**
|
|
3719
|
+
* Insert records using values produced by another query/source while ignoring insertion errors.
|
|
3720
|
+
*
|
|
3721
|
+
* @param columns
|
|
3722
|
+
* @param query
|
|
3723
|
+
* @returns
|
|
3724
|
+
*/
|
|
3725
|
+
async insertOrIgnoreUsing(columns, query) {
|
|
3726
|
+
const rows = await this.resolveInsertUsingRows(columns, query);
|
|
3727
|
+
if (rows.length === 0) return 0;
|
|
3728
|
+
return this.insertOrIgnore(rows);
|
|
3729
|
+
}
|
|
3730
|
+
/**
|
|
3638
3731
|
* Updates records matching the current query constraints with the
|
|
3639
3732
|
* specified data and returns the updated record(s) as model instance(s).
|
|
3640
3733
|
*
|
|
@@ -3652,6 +3745,71 @@ var QueryBuilder = class QueryBuilder {
|
|
|
3652
3745
|
return this.model.hydrate(updated);
|
|
3653
3746
|
}
|
|
3654
3747
|
/**
|
|
3748
|
+
* Update records using update-many semantics when available.
|
|
3749
|
+
*
|
|
3750
|
+
* @param data
|
|
3751
|
+
* @returns
|
|
3752
|
+
*/
|
|
3753
|
+
async updateFrom(data) {
|
|
3754
|
+
const where = this.buildWhere();
|
|
3755
|
+
if (!where) throw new ArkormException("Update requires a where clause.");
|
|
3756
|
+
const delegate = this.delegate;
|
|
3757
|
+
if (typeof delegate.updateMany === "function") {
|
|
3758
|
+
const result = await delegate.updateMany({
|
|
3759
|
+
where,
|
|
3760
|
+
data
|
|
3761
|
+
});
|
|
3762
|
+
return this.resolveAffectedCount(result, 0);
|
|
3763
|
+
}
|
|
3764
|
+
await this.update(data);
|
|
3765
|
+
return 1;
|
|
3766
|
+
}
|
|
3767
|
+
/**
|
|
3768
|
+
* Insert a record when no match exists, otherwise update the matching record.
|
|
3769
|
+
*
|
|
3770
|
+
* @param attributes
|
|
3771
|
+
* @param values
|
|
3772
|
+
* @returns
|
|
3773
|
+
*/
|
|
3774
|
+
async updateOrInsert(attributes, values = {}) {
|
|
3775
|
+
const exists = await this.delegate.findFirst({ where: attributes }) != null;
|
|
3776
|
+
const resolvedValues = typeof values === "function" ? await values(exists) : values;
|
|
3777
|
+
if (!exists) {
|
|
3778
|
+
await this.delegate.create({ data: {
|
|
3779
|
+
...attributes,
|
|
3780
|
+
...resolvedValues
|
|
3781
|
+
} });
|
|
3782
|
+
return true;
|
|
3783
|
+
}
|
|
3784
|
+
return await this.clone().where(attributes).update(resolvedValues) != null;
|
|
3785
|
+
}
|
|
3786
|
+
/**
|
|
3787
|
+
* Insert new records or update existing records by one or more unique keys.
|
|
3788
|
+
*
|
|
3789
|
+
* @param values
|
|
3790
|
+
* @param uniqueBy
|
|
3791
|
+
* @param update
|
|
3792
|
+
* @returns
|
|
3793
|
+
*/
|
|
3794
|
+
async upsert(values, uniqueBy, update = null) {
|
|
3795
|
+
if (values.length === 0) return 0;
|
|
3796
|
+
const uniqueKeys = Array.isArray(uniqueBy) ? uniqueBy : [uniqueBy];
|
|
3797
|
+
let affected = 0;
|
|
3798
|
+
for (const row of values) {
|
|
3799
|
+
const attributes = uniqueKeys.reduce((all, key) => {
|
|
3800
|
+
all[key] = row[key];
|
|
3801
|
+
return all;
|
|
3802
|
+
}, {});
|
|
3803
|
+
const updatePayload = (update ?? Object.keys(row).filter((key) => !uniqueKeys.includes(key))).reduce((all, key) => {
|
|
3804
|
+
if (key in row) all[key] = row[key];
|
|
3805
|
+
return all;
|
|
3806
|
+
}, {});
|
|
3807
|
+
await this.updateOrInsert(attributes, updatePayload);
|
|
3808
|
+
affected += 1;
|
|
3809
|
+
}
|
|
3810
|
+
return affected;
|
|
3811
|
+
}
|
|
3812
|
+
/**
|
|
3655
3813
|
* Deletes records matching the current query constraints and returns
|
|
3656
3814
|
* the deleted record(s) as model instance(s).
|
|
3657
3815
|
*
|
|
@@ -3690,6 +3848,43 @@ var QueryBuilder = class QueryBuilder {
|
|
|
3690
3848
|
async doesntExist() {
|
|
3691
3849
|
return !await this.exists();
|
|
3692
3850
|
}
|
|
3851
|
+
normalizeInsertPayloads(values) {
|
|
3852
|
+
if (Array.isArray(values)) return values;
|
|
3853
|
+
return [values];
|
|
3854
|
+
}
|
|
3855
|
+
resolveAffectedCount(result, fallback) {
|
|
3856
|
+
if (typeof result === "number") return result;
|
|
3857
|
+
if (result && typeof result === "object" && "count" in result) {
|
|
3858
|
+
const candidate = result.count;
|
|
3859
|
+
if (typeof candidate === "number") return candidate;
|
|
3860
|
+
}
|
|
3861
|
+
return fallback;
|
|
3862
|
+
}
|
|
3863
|
+
async resolveInsertUsingRows(columns, query) {
|
|
3864
|
+
const resolvedQuery = typeof query === "function" ? await query() : query;
|
|
3865
|
+
return (await this.resolveInsertUsingSource(resolvedQuery)).map((row) => {
|
|
3866
|
+
return columns.reduce((record, column) => {
|
|
3867
|
+
record[column] = row[column];
|
|
3868
|
+
return record;
|
|
3869
|
+
}, {});
|
|
3870
|
+
});
|
|
3871
|
+
}
|
|
3872
|
+
async resolveInsertUsingSource(source) {
|
|
3873
|
+
if (source && typeof source === "object") {
|
|
3874
|
+
const asBuilder = source;
|
|
3875
|
+
if (typeof asBuilder.get === "function") {
|
|
3876
|
+
const collection = await asBuilder.get();
|
|
3877
|
+
if (typeof collection.all === "function") return collection.all().map((item) => {
|
|
3878
|
+
const asModel = item;
|
|
3879
|
+
if (typeof asModel.getRawAttributes === "function") return asModel.getRawAttributes();
|
|
3880
|
+
return item;
|
|
3881
|
+
});
|
|
3882
|
+
}
|
|
3883
|
+
if (Array.isArray(source)) return source;
|
|
3884
|
+
}
|
|
3885
|
+
if (Array.isArray(source)) return source;
|
|
3886
|
+
throw new ArkormException("insertUsing expects a query builder, array of records, or async resolver.");
|
|
3887
|
+
}
|
|
3693
3888
|
/**
|
|
3694
3889
|
* Execute callback when no records exist.
|
|
3695
3890
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arkormx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Modern TypeScript-first ORM for Node.js.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"orm",
|
|
@@ -72,9 +72,11 @@
|
|
|
72
72
|
"@h3ravel/musket": "^0.10.1",
|
|
73
73
|
"@h3ravel/shared": "^0.27.13",
|
|
74
74
|
"@h3ravel/support": "^0.15.11",
|
|
75
|
-
"@prisma/client": "^7.4.2",
|
|
76
75
|
"dotenv": "^17.3.1"
|
|
77
76
|
},
|
|
77
|
+
"peerDependencies": {
|
|
78
|
+
"@prisma/client": "^7.4.2"
|
|
79
|
+
},
|
|
78
80
|
"scripts": {
|
|
79
81
|
"cmd": "tsx src/cli/index.ts",
|
|
80
82
|
"lint": "eslint",
|