Skip to content

Commit d65d437

Browse files
committed
Updated sqobjects
1 parent 91d9738 commit d65d437

File tree

12 files changed

+399
-178
lines changed

12 files changed

+399
-178
lines changed

npm/sqlite3/html/index.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,14 @@
3838
<h1 class="_name">[schema]</h1>
3939
<small class="_filename">[filename]</small>
4040
</div>
41+
<!-- NAV TABS -->
4142
<ul class="nav nav-tabs" id="schema-table-list">
4243
<li class="nav-item _template">
4344
<a class="nav-link _name" aria-current="page" href="#">[table]</a>
4445
</li>
4546
</ul>
47+
<!-- NAV TABS II -->
48+
<nav-view class="nav-tabs" id="schema-table-nav"></nav-view>
4649
<!-- TABLE CONTENT (TableView) -->
4750
<div class="m-2">
4851
<table-view cols="Col A, Col B, Col C"></table-view>

npm/sqlite3/js/controller/app.js

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ export default class App extends Controller {
2323
constructor() {
2424
super();
2525

26+
// Get nodes for the web components
27+
const schemaTableNav = document.querySelector('#schema-table-nav');
28+
2629
// VIEWS
2730
const navNode = document.querySelector('#nav');
2831
if (navNode) {
@@ -51,7 +54,6 @@ export default class App extends Controller {
5154
super.define('schemaview', new SchemaView(schemaNode));
5255
this.schemaview.addEventListener(['schema:change'], () => {
5356
console.log('schema:change');
54-
5557
// Set active table to the first table in the schema
5658
});
5759
this.schemaview.addEventListener(['schema:click'], (sender, target) => {
@@ -108,6 +110,17 @@ export default class App extends Controller {
108110
this.schema.addEventListener(['provider:added', 'provider:changed'], (sender, schema) => {
109111
console.log(`schema added: ${schema}`);
110112
this.schemaview.schema = schema;
113+
// Add the tabs
114+
if (schemaTableNav) {
115+
schema.tables.forEach((table) => {
116+
const tab = document.createElement('nav-item-view');
117+
tab.textContent = table.name;
118+
tab.id = table.key;
119+
tab.classList.add('nav-link');
120+
schemaTableNav.appendChild(tab);
121+
});
122+
schemaTableNav.update();
123+
}
111124
});
112125
this.schema.addEventListener('provider:deleted', (sender, schema) => {
113126
console.log(`schema deleted: ${schema}`);
@@ -120,6 +133,24 @@ export default class App extends Controller {
120133
this.tabledata.addEventListener(['provider:added', 'provider:changed'], (sender, data) => {
121134
console.log(`data added: ${data}`);
122135
});
136+
137+
// NEW STUFF
138+
if (schemaTableNav) {
139+
schemaTableNav.addEventListener('nav-view:click', (evt) => {
140+
// When click on a tab, make it active
141+
schemaTableNav.active = evt.detail;
142+
});
143+
schemaTableNav.addEventListener('nav-view:active', (evt) => {
144+
// Fire when the tab is active
145+
console.log(`schema-table-nav active: ${evt.detail}`);
146+
});
147+
schemaTableNav.addEventListener('nav-view:deactive', (evt) => {
148+
// Fire when the tab has been deactivated
149+
console.log(`schema-table-nav deactive: ${evt.detail}`);
150+
// Disconnect from parent
151+
//schemaTableNav.removeChild(evt.detail);
152+
});
153+
}
123154
}
124155

125156
main() {

npm/sqlite3/js/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import '../css/index.css';
66
import App from './controller/app';
77

88
// Views
9+
import './view/nav-view';
10+
import './view/nav-item-view';
11+
912
import './view/table-view';
1013
import './view/table-head-view';
1114
import './view/table-body-view';

pkg/sqobj/sqclass.go

Lines changed: 86 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ type Class struct {
1717
SQSource
1818

1919
// Prepared statements and in-place parameters
20-
s map[SQKey]SQStatement
20+
s map[stkey]SQStatement
2121
p []interface{}
2222
}
2323

@@ -38,7 +38,7 @@ func MustRegisterClass(source SQSource, proto interface{}) *Class {
3838
// any errors
3939
func RegisterClass(source SQSource, proto interface{}) (*Class, error) {
4040
this := new(Class)
41-
this.s = make(map[SQKey]SQStatement)
41+
this.s = make(map[stkey]SQStatement)
4242

4343
// Check name
4444
if source.Name() == "" {
@@ -165,7 +165,7 @@ func (c *Class) Insert(txn SQTransaction, v ...interface{}) ([]int64, error) {
165165
if !rv.IsValid() || rv.Type() != c.t {
166166
return nil, ErrBadParameter.Withf("Insert: %v", v)
167167
}
168-
r, err := txn.Query(st, c.boundValues(rv, true)...)
168+
r, err := txn.Query(st, c.boundValues(rv, true, false)...)
169169
if err != nil {
170170
return nil, err
171171
}
@@ -244,24 +244,101 @@ func (c *Class) DeleteKeys(txn SQTransaction, v ...interface{}) (int, error) {
244244
return n, nil
245245
}
246246

247+
// Update objects by primary key, return number of updated rows
248+
func (c *Class) UpdateKeys(txn SQTransaction, v ...interface{}) (int, error) {
249+
// Retrieve prepared statement
250+
st, exists := c.s[SQKeyUpdateKeys]
251+
if !exists {
252+
return 0, ErrOutOfOrder.Withf("UpdateKeys: %q", c.Name())
253+
}
254+
255+
// Update each object
256+
var n int
257+
for _, v := range v {
258+
rv := ValueOf(v)
259+
if !rv.IsValid() || rv.Type() != c.t {
260+
return 0, ErrBadParameter.Withf("UpdateKeys: %v", v)
261+
}
262+
r, err := txn.Query(st, c.boundValues(rv, false, true)...)
263+
if err != nil {
264+
return 0, err
265+
}
266+
n += r.RowsAffected()
267+
}
268+
269+
// Return success
270+
return n, nil
271+
}
272+
273+
func (c *Class) UpsertKeys(txn SQTransaction, v ...interface{}) ([]int64, error) {
274+
result := make([]int64, 0, len(v))
275+
276+
// Retrieve prepared statement
277+
st, exists := c.s[SQKeyUpsertKeys]
278+
if !exists {
279+
return nil, ErrOutOfOrder.Withf("UpdateKeys: %q", c.Name())
280+
}
281+
282+
// Update each object
283+
for _, v := range v {
284+
rv := ValueOf(v)
285+
if !rv.IsValid() || rv.Type() != c.t {
286+
return nil, ErrBadParameter.Withf("UpdateKeys: %v", v)
287+
}
288+
r, err := txn.Query(st, c.boundValues(rv, true, false)...)
289+
if err != nil {
290+
return nil, err
291+
}
292+
if r.RowsAffected() > 0 {
293+
if r.LastInsertId() == 0 {
294+
fmt.Println("TODO: Set last insert id as rows affected (was an update)")
295+
result = append(result, -1)
296+
} else {
297+
result = append(result, r.LastInsertId())
298+
}
299+
} else {
300+
result = append(result, 0)
301+
}
302+
}
303+
304+
// Return success
305+
return result, nil
306+
}
307+
247308
///////////////////////////////////////////////////////////////////////////////
248309
// PRIVATE METHODS
249310

250311
// boundValues returns sqlite-compatible values for a struct value. If autonull
251312
// argument is true, then any zero-value column is set to NULL. This is so inserts
252-
// can be performed.
253-
func (this *Class) boundValues(v reflect.Value, autonull bool) []interface{} {
313+
// can be performed. If primarylast is true, then primary values are put behind non-
314+
// primary values.
315+
func (this *Class) boundValues(v reflect.Value, autonull bool, primarylast bool) []interface{} {
254316
// Set length of parameters
255317
this.p = this.p[:len(this.col)]
256318

257-
// Iterate over columns
258-
for i, col := range this.col {
319+
// First iteration sets values
320+
j := 0
321+
if primarylast {
322+
for _, col := range this.col {
323+
field := v.Field(col.Field.Index)
324+
if !col.Primary {
325+
this.p[j] = field.Interface()
326+
j++
327+
}
328+
}
329+
}
330+
331+
for _, col := range this.col {
259332
field := v.Field(col.Field.Index)
333+
if primarylast && !col.Primary {
334+
continue
335+
}
260336
if autonull && col.Auto && field.IsZero() {
261-
this.p[i] = nil
337+
this.p[j] = nil
262338
} else {
263-
this.p[i] = field.Interface()
339+
this.p[j] = field.Interface()
264340
}
341+
j++
265342
}
266343

267344
// Return success

pkg/sqobj/sqclass_statements.go

Lines changed: 32 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,30 @@ import (
1111
// TYPES
1212

1313
type sqpreparefunc func(*Class, SQTransaction) SQStatement
14+
type stkey uint
1415

1516
///////////////////////////////////////////////////////////////////////////////
1617
// GLOBALS
1718

19+
const (
20+
SQKeyNone stkey = iota
21+
SQKeySelect
22+
SQKeyInsert
23+
SQKeyDeleteRows
24+
SQKeyDeleteKeys
25+
SQKeyUpdateKeys
26+
SQKeyUpsertKeys
27+
SQKeyMax = SQKeyUpdateKeys
28+
)
29+
1830
var (
19-
statements = map[SQKey]sqpreparefunc{
31+
statements = map[stkey]sqpreparefunc{
2032
SQKeySelect: sqSelect,
2133
SQKeyInsert: sqInsert,
2234
SQKeyDeleteRows: sqDeleteRows,
2335
SQKeyDeleteKeys: sqDeleteKeys,
36+
SQKeyUpdateKeys: sqUpdateKeys,
37+
SQKeyUpsertKeys: sqUpsertKeys,
2438
}
2539
)
2640

@@ -59,99 +73,27 @@ func sqDeleteKeys(class *Class, _ SQTransaction) SQStatement {
5973
return class.SQSource.Delete(cols...)
6074
}
6175

62-
/*
63-
64-
func (this *sqclass) addStatements(flags SQFlag) error {
65-
this.RWMutex.Lock()
66-
defer this.RWMutex.Unlock()
67-
68-
// Create statments for create,insert and delete
69-
this.addStatement(SQKeyCreate, this.sqCreate())
70-
this.addStatement(SQKeyWrite, this.sqInsert(flags))
71-
this.addStatement(SQKeyRead, this.sqSelect())
72-
73-
// If we have primary keys, other operations are possible
74-
if len(this.PrimaryColumnNames()) > 0 {
75-
this.addStatement(SQKeyDelete, this.sqDelete())
76-
this.addStatement(SQKeyGetRowId, this.sqGetRowId())
77-
}
78-
79-
// Create index statements
80-
for _, index := range this.indexes {
81-
this.addStatement(SQKeyCreate, this.sqIndex(index))
82-
}
83-
84-
// Return success
85-
return nil
86-
}
87-
88-
func (this *sqclass) addStatement(key SQKey, st SQStatement) {
89-
this.s[key] = append(this.s[key], st)
90-
}
91-
92-
func (this *sqclass) sqCreate() SQTable {
93-
st := this.CreateTable(this.Columns()...).IfNotExists()
94-
for _, column := range this.columns {
95-
if column.Unique {
96-
st = st.WithUnique(column.Field.Name)
97-
} else if column.Index {
98-
st = st.WithIndex(column.Field.Name)
76+
func sqUpdateKeys(class *Class, _ SQTransaction) SQStatement {
77+
values := make([]string, 0, len(class.col))
78+
keys := make([]interface{}, 0, len(class.col))
79+
for _, c := range class.col {
80+
if !c.Primary {
81+
values = append(values, c.Col.Name())
82+
} else {
83+
keys = append(keys, Q(N(c.Col.Name()), "=", P))
9984
}
10085
}
101-
return st
102-
}
103-
104-
func (this *sqclass) sqIndex(index *sqindex) SQStatement {
105-
st := N(this.Name()+"_"+index.name).
106-
WithSchema(this.Schema()).
107-
CreateIndex(this.Name(), index.cols...).IfNotExists()
108-
if index.unique {
109-
st = st.WithUnique()
110-
}
111-
return st
86+
return class.SQSource.Update(values...).Where(keys...)
11287
}
11388

114-
func (this *sqclass) sqInsert(flags SQFlag) SQStatement {
115-
st := this.Insert(this.ColumnNames()...)
116-
117-
// Add conflict resolution for any primary key field
118-
st = st.WithConflictUpdate(this.PrimaryColumnNames()...)
119-
120-
// Add conflict resolution for any unique fields
121-
for _, column := range this.columns {
122-
if column.Unique && flags&SQLITE_FLAG_UPDATEONINSERT != 0 {
123-
st = st.WithConflictUpdate(column.Field.Name)
124-
}
125-
}
126-
127-
// Add conflict for any unique indexes
128-
for _, index := range this.indexes {
129-
if index.unique && flags&SQLITE_FLAG_UPDATEONINSERT != 0 {
130-
st = st.WithConflictUpdate(index.cols...)
89+
func sqUpsertKeys(class *Class, _ SQTransaction) SQStatement {
90+
cols := make([]string, len(class.col))
91+
keys := make([]string, 0, len(class.col))
92+
for i, col := range class.col {
93+
cols[i] = col.Col.Name()
94+
if col.Primary {
95+
keys = append(keys, col.Col.Name())
13196
}
13297
}
133-
134-
// Return success
135-
return st
136-
}
137-
138-
func (this *sqclass) sqDelete() SQStatement {
139-
expr := []interface{}{}
140-
for _, name := range this.PrimaryColumnNames() {
141-
expr = append(expr, Q(N(name), "=", P))
142-
}
143-
return this.Delete(expr...)
144-
}
145-
146-
func (this *sqclass) sqGetRowId() SQStatement {
147-
expr := []interface{}{}
148-
for _, name := range this.PrimaryColumnNames() {
149-
expr = append(expr, Q(N(name), "=", P))
150-
}
151-
return S(this.SQSource).To(N("rowid")).Where(expr...)
152-
}
153-
154-
func (this *sqclass) sqSelect() SQStatement {
155-
return S(this.SQSource).To(this.ColumnSources()...)
98+
return class.SQSource.Insert(cols...).WithConflictUpdate(keys...)
15699
}
157-
*/

0 commit comments

Comments
 (0)